diff options
author | Ben Murdoch <benm@google.com> | 2011-05-16 16:25:10 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-23 18:54:14 +0100 |
commit | ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb (patch) | |
tree | db769fadd053248f85db67434a5b275224defef7 /Source/JavaScriptCore/runtime | |
parent | 52e2557aeb8477967e97fd24f20f8f407a10fa15 (diff) | |
download | external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.zip external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.gz external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.bz2 |
Merge WebKit at r76408: Initial merge by git.
Change-Id: I5b91decbd693ccbf5c1b8354b37cd68cc9a1ea53
Diffstat (limited to 'Source/JavaScriptCore/runtime')
33 files changed, 292 insertions, 151 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index cd563a2..57e3c20 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -25,14 +25,14 @@ #include "CallFrame.h" #include "Register.h" #include <wtf/HashSet.h> -#include <wtf/Noncopyable.h> #include <wtf/Vector.h> namespace JSC { class MarkStack; - class MarkedArgumentBuffer : public Noncopyable { + class MarkedArgumentBuffer { + WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); private: static const unsigned inlineCapacity = 8; typedef Vector<Register, inlineCapacity> VectorType; diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 715a2ac..fe900a2 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -33,7 +33,10 @@ namespace JSC { - struct ArgumentsData : Noncopyable { + struct ArgumentsData { + WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED; + public: + ArgumentsData() { } JSActivation* activation; unsigned numParameters; diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index ab0c3d4..7615ffc 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -32,6 +32,7 @@ #include "Lookup.h" #include "ObjectPrototype.h" #include "Operations.h" +#include "StringRecursionChecker.h" #include <algorithm> #include <wtf/Assertions.h> #include <wtf/HashSet.h> @@ -168,15 +169,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) return throwVMTypeError(exec); JSArray* thisObj = asArray(thisValue); - HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { - if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) - return throwVMError(exec, createStackOverflowError(exec)); - } - - bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; - if (alreadyVisited) - return JSValue::encode(jsEmptyString(exec)); // return an empty string, avoiding infinite recursion. + StringRecursionChecker checker(exec, thisObj); + if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) + return earlyReturnValue; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned totalSize = length ? length - 1 : 0; @@ -209,7 +204,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) if (exec->hadException()) break; } - arrayVisitedElements.remove(thisObj); if (!totalSize) return JSValue::encode(jsEmptyString(exec)); Vector<UChar> buffer; @@ -234,15 +228,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) return throwVMTypeError(exec); JSObject* thisObj = asArray(thisValue); - HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { - if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) - return throwVMError(exec, createStackOverflowError(exec)); - } - - bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; - if (alreadyVisited) - return JSValue::encode(jsEmptyString(exec)); // return an empty string, avoding infinite recursion. + StringRecursionChecker checker(exec, thisObj); + if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) + return earlyReturnValue; JSStringBuilder strBuffer; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); @@ -264,7 +252,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) strBuffer.append(str); } } - arrayVisitedElements.remove(thisObj); + return JSValue::encode(strBuffer.build(exec)); } @@ -272,15 +260,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { - if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) - return throwVMError(exec, createStackOverflowError(exec)); - } - - bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; - if (alreadyVisited) - return JSValue::encode(jsEmptyString(exec)); // return an empty string, avoding infinite recursion. + StringRecursionChecker checker(exec, thisObj); + if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) + return earlyReturnValue; JSStringBuilder strBuffer; @@ -335,7 +317,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) if (!element.isUndefinedOrNull()) strBuffer.append(element.toString(exec)); } - arrayVisitedElements.remove(thisObj); + return JSValue::encode(strBuffer.build(exec)); } diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 74089a5..db2d1d7 100644 --- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -27,12 +27,12 @@ #ifndef BatchedTransitionOptimizer_h #define BatchedTransitionOptimizer_h -#include <wtf/Noncopyable.h> #include "JSObject.h" namespace JSC { - class BatchedTransitionOptimizer : public Noncopyable { + class BatchedTransitionOptimizer { + WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer); public: BatchedTransitionOptimizer(JSObject* object) : m_object(object) diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index 1e22b6a..6587a8f 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -84,7 +84,8 @@ namespace JSC { - class CommonIdentifiers : public Noncopyable { + class CommonIdentifiers { + WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED; private: CommonIdentifiers(JSGlobalData*); friend class JSGlobalData; diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index d18e7d8..d8fc829 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -26,6 +26,7 @@ #include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "PrototypeFunction.h" +#include "StringRecursionChecker.h" #include "UString.h" namespace JSC { @@ -47,6 +48,11 @@ ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, No EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + + StringRecursionChecker checker(exec, thisObj); + if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) + return earlyReturnValue; + JSValue name = thisObj->get(exec, exec->propertyNames().name); JSValue message = thisObj->get(exec, exec->propertyNames().message); diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp index a224ee0..3966324 100644 --- a/Source/JavaScriptCore/runtime/Heap.cpp +++ b/Source/JavaScriptCore/runtime/Heap.cpp @@ -41,7 +41,8 @@ Heap::Heap(JSGlobalData* globalData) , m_markListSet(0) , m_activityCallback(DefaultGCActivityCallback::create(this)) , m_globalData(globalData) - , m_machineStackMarker(&globalData->heap) + , m_machineStackMarker(this) + , m_markStack(globalData->jsArrayVPtr) , m_extraCost(0) { (*m_activityCallback)(); @@ -93,12 +94,6 @@ void Heap::recordExtraCost(size_t cost) if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.size() / 2) { JAVASCRIPTCORE_GC_BEGIN(); - // If the last iteration through the heap deallocated blocks, we need - // to clean up remaining garbage before marking. Otherwise, the conservative - // marking mechanism might follow a pointer to unmapped memory. - if (m_markedSpace.didShrink()) - m_markedSpace.sweep(); - markRoots(); JAVASCRIPTCORE_GC_MARKED(); @@ -152,9 +147,9 @@ void* Heap::allocate(size_t s) return result; } -void Heap::markConservatively(MarkStack& markStack, void* start, void* end) +void Heap::markConservatively(ConservativeSet& conservativeSet, void* start, void* end) { - m_markedSpace.markConservatively(markStack, start, end); + m_markedSpace.markConservatively(conservativeSet, start, end); } void Heap::updateWeakGCHandles() @@ -212,10 +207,8 @@ bool Heap::unprotect(JSValue k) void Heap::markProtectedObjects(MarkStack& markStack) { ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { + for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) markStack.append(it->first); - markStack.drain(); - } } void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector) @@ -238,10 +231,10 @@ void Heap::markTempSortVectors(MarkStack& markStack) Vector<ValueStringPair>* tempSortingVector = *it; Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end(); - for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) + for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) { if (vectorIt->first) markStack.append(vectorIt->first); - markStack.drain(); + } } } @@ -260,20 +253,27 @@ void Heap::markRoots() m_operationInProgress = Collection; - MarkStack& markStack = m_globalData->markStack; + // We gather the conservative set before clearing mark bits, because + // conservative gathering uses the mark bits from our last mark pass to + // determine whether a reference is valid. + ConservativeSet conservativeSet; + m_machineStackMarker.markMachineStackConservatively(conservativeSet); + m_globalData->interpreter->registerFile().markCallFrames(conservativeSet, this); // Reset mark bits. m_markedSpace.clearMarkBits(); - // Mark stack roots. - m_machineStackMarker.markMachineStackConservatively(markStack); - m_globalData->interpreter->registerFile().markCallFrames(markStack, this); + MarkStack& markStack = m_markStack; + conservativeSet.mark(markStack); + markStack.drain(); // Mark explicitly registered roots. markProtectedObjects(markStack); + markStack.drain(); // Mark temporary vector for Array sorting markTempSortVectors(markStack); + markStack.drain(); // Mark misc. other roots. if (m_markListSet && m_markListSet->size()) @@ -282,6 +282,7 @@ void Heap::markRoots() markStack.append(m_globalData->exception); if (m_globalData->firstStringifierToMark) JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); + markStack.drain(); // Mark the small strings cache last, since it will clear itself if nothing // else has marked it. @@ -392,12 +393,6 @@ void Heap::collectAllGarbage() ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); JAVASCRIPTCORE_GC_BEGIN(); - // If the last iteration through the heap deallocated blocks, we need - // to clean up remaining garbage before marking. Otherwise, the conservative - // marking mechanism might follow a pointer to unmapped memory. - if (m_markedSpace.didShrink()) - m_markedSpace.sweep(); - markRoots(); JAVASCRIPTCORE_GC_MARKED(); diff --git a/Source/JavaScriptCore/runtime/Heap.h b/Source/JavaScriptCore/runtime/Heap.h index 243bba3..f7f4deb 100644 --- a/Source/JavaScriptCore/runtime/Heap.h +++ b/Source/JavaScriptCore/runtime/Heap.h @@ -22,6 +22,7 @@ #ifndef Heap_h #define Heap_h +#include "MarkStack.h" #include "MarkedSpace.h" #include <wtf/Forward.h> #include <wtf/HashSet.h> @@ -45,7 +46,8 @@ namespace JSC { enum OperationInProgress { NoOperation, Allocation, Collection }; - class Heap : public Noncopyable { + class Heap { + WTF_MAKE_NONCOPYABLE(Heap); public: void destroy(); @@ -86,7 +88,7 @@ namespace JSC { WeakGCHandle* addWeakGCHandle(JSCell*); - void markConservatively(MarkStack&, void* start, void* end); + void markConservatively(ConservativeSet&, void* start, void* end); void pushTempSortVector(WTF::Vector<ValueStringPair>*); void popTempSortVector(WTF::Vector<ValueStringPair>*); @@ -130,6 +132,7 @@ namespace JSC { JSGlobalData* m_globalData; MachineStackMarker m_machineStackMarker; + MarkStack m_markStack; size_t m_extraCost; }; diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 1147858..428403d 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -53,6 +53,7 @@ void JSActivation::markChildren(MarkStack& markStack) { Base::markChildren(markStack); + // No need to mark our registers if they're still in the RegisterFile. Register* registerArray = d()->registerArray.get(); if (!registerArray) return; @@ -202,14 +203,16 @@ JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identi JSActivation* activation = asActivation(slotBase); CallFrame* callFrame = CallFrame::create(activation->d()->registers); int argumentsRegister = activation->d()->functionExecutable->generatedBytecode().argumentsRegister(); - if (!callFrame->uncheckedR(argumentsRegister).jsValue()) { - JSValue arguments = JSValue(new (callFrame) Arguments(callFrame)); - callFrame->uncheckedR(argumentsRegister) = arguments; - callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = arguments; - } + if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue()) + return arguments; + int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister); - ASSERT(callFrame->uncheckedR(argumentsRegister).jsValue().inherits(&Arguments::info)); - return callFrame->uncheckedR(argumentsRegister).jsValue(); + JSValue arguments = JSValue(new (callFrame) Arguments(callFrame)); + callFrame->uncheckedR(argumentsRegister) = arguments; + callFrame->uncheckedR(realArgumentsRegister) = arguments; + + ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::info)); + return callFrame->uncheckedR(realArgumentsRegister).jsValue(); } // These two functions serve the purpose of isolating the common case from a diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index f20a9a4..3928c82 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -143,7 +143,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , head(0) , dynamicGlobalObject(0) , firstStringifierToMark(0) - , markStack(jsArrayVPtr) , cachedUTCOffset(NaN) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) , m_regExpCache(new RegExpCache(this)) diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index a24732a..31f41e9 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -35,7 +35,6 @@ #include "ExecutableAllocator.h" #include "JITStubs.h" #include "JSValue.h" -#include "MarkStack.h" #include "NumericStrings.h" #include "SmallStrings.h" #include "Terminator.h" @@ -214,12 +213,10 @@ namespace JSC { JSGlobalObject* head; JSGlobalObject* dynamicGlobalObject; - HashSet<JSObject*> arrayVisitedElements; + HashSet<JSObject*> stringRecursionCheckVisitedObjects; Stringifier* firstStringifierToMark; - MarkStack markStack; - double cachedUTCOffset; DSTOffsetCache dstOffsetCache; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 408aea7..9b67dbb 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -349,10 +349,6 @@ void JSGlobalObject::markChildren(MarkStack& markStack) for (HashSet<GlobalCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) (*it)->markAggregate(markStack); - RegisterFile& registerFile = globalData().interpreter->registerFile(); - if (registerFile.globalObject() == this) - registerFile.markGlobals(markStack, &globalData().heap); - markIfNeeded(markStack, d()->regExpConstructor); markIfNeeded(markStack, d()->errorConstructor); markIfNeeded(markStack, d()->evalErrorConstructor); @@ -397,12 +393,16 @@ void JSGlobalObject::markChildren(MarkStack& markStack) // No need to mark the other structures, because their prototypes are all // guaranteed to be referenced elsewhere. - Register* registerArray = d()->registerArray.get(); - if (!registerArray) - return; - - size_t size = d()->registerArraySize; - markStack.appendValues(reinterpret_cast<JSValue*>(registerArray), size); + if (d()->registerArray) { + // Outside the execution of global code, when our variables are torn off, + // we can mark the torn-off array. + markStack.appendValues(d()->registerArray.get(), d()->registerArraySize); + } else if (d()->registers) { + // During execution of global code, when our variables are in the register file, + // the symbol table tells us how many variables there are, and registers + // points to where they end, and the registers used for execution begin. + markStack.appendValues(d()->registers - symbolTable().size(), symbolTable().size()); + } } ExecState* JSGlobalObject::globalExec() diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index a22b0aa..24bc2f8 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -465,7 +465,8 @@ namespace JSC { return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); } - class DynamicGlobalObjectScope : public Noncopyable { + class DynamicGlobalObjectScope { + WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope); public: DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject); diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h index 05b388c..7b07b4f 100644 --- a/Source/JavaScriptCore/runtime/JSLock.h +++ b/Source/JavaScriptCore/runtime/JSLock.h @@ -53,7 +53,8 @@ namespace JSC { enum JSLockBehavior { SilenceAssertionsOnly, LockForReal }; - class JSLock : public Noncopyable { + class JSLock { + WTF_MAKE_NONCOPYABLE(JSLock); public: JSLock(ExecState*); JSLock(JSGlobalData*); @@ -89,7 +90,8 @@ namespace JSC { JSLockBehavior m_lockBehavior; - class DropAllLocks : public Noncopyable { + class DropAllLocks { + WTF_MAKE_NONCOPYABLE(DropAllLocks); public: DropAllLocks(ExecState* exec); DropAllLocks(JSLockBehavior); diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index 9e63027..df4be52 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -70,7 +70,8 @@ private: mutable JSValue m_value; }; -class Stringifier : public Noncopyable { +class Stringifier { + WTF_MAKE_NONCOPYABLE(Stringifier); public: Stringifier(ExecState*, JSValue replacer, JSValue space); ~Stringifier(); diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index 9bc81d4..0d6d98f 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -53,7 +53,8 @@ namespace JSC { typedef PropertySlot::GetValueFunc GetFunction; typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value); - class HashEntry : public FastAllocBase { + class HashEntry { + WTF_MAKE_FAST_ALLOCATED; public: void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2 #if ENABLE(JIT) diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp index b4a1936..e52f402 100644 --- a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp @@ -194,10 +194,9 @@ void MachineStackMarker::unregisterThread() #endif -void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(MarkStack& markStack) +void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(ConservativeSet& conservativeSet) { - m_heap->markConservatively(markStack, m_heap->globalData()->stack().current(), m_heap->globalData()->stack().origin()); - markStack.drain(); + m_heap->markConservatively(conservativeSet, m_heap->globalData()->stack().current(), m_heap->globalData()->stack().origin()); } #if COMPILER(GCC) @@ -206,7 +205,7 @@ void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(Ma #define REGISTER_BUFFER_ALIGNMENT #endif -void MachineStackMarker::markCurrentThreadConservatively(MarkStack& markStack) +void MachineStackMarker::markCurrentThreadConservatively(ConservativeSet& conservativeSet) { // setjmp forces volatile registers onto the stack jmp_buf registers REGISTER_BUFFER_ALIGNMENT; @@ -219,7 +218,7 @@ void MachineStackMarker::markCurrentThreadConservatively(MarkStack& markStack) #pragma warning(pop) #endif - markCurrentThreadConservativelyInternal(markStack); + markCurrentThreadConservativelyInternal(conservativeSet); } #if ENABLE(JSC_MULTIPLE_THREADS) @@ -351,7 +350,7 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) #endif } -void MachineStackMarker::markOtherThreadConservatively(MarkStack& markStack, Thread* thread) +void MachineStackMarker::markOtherThreadConservatively(ConservativeSet& conservativeSet, Thread* thread) { suspendThread(thread->platformThread); @@ -359,21 +358,19 @@ void MachineStackMarker::markOtherThreadConservatively(MarkStack& markStack, Thr size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); // mark the thread's registers - m_heap->markConservatively(markStack, static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); - markStack.drain(); + m_heap->markConservatively(conservativeSet, static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); void* stackPointer = otherThreadStackPointer(regs); - m_heap->markConservatively(markStack, stackPointer, thread->stackBase); - markStack.drain(); + m_heap->markConservatively(conservativeSet, stackPointer, thread->stackBase); resumeThread(thread->platformThread); } #endif -void MachineStackMarker::markMachineStackConservatively(MarkStack& markStack) +void MachineStackMarker::markMachineStackConservatively(ConservativeSet& conservativeSet) { - markCurrentThreadConservatively(markStack); + markCurrentThreadConservatively(conservativeSet); #if ENABLE(JSC_MULTIPLE_THREADS) @@ -391,7 +388,7 @@ void MachineStackMarker::markMachineStackConservatively(MarkStack& markStack) // and since this is a shared heap, they are real locks. for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (!pthread_equal(thread->posixThread, pthread_self())) - markOtherThreadConservatively(markStack, thread); + markOtherThreadConservatively(conservativeSet, thread); } #ifndef NDEBUG fastMallocAllow(); diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.h b/Source/JavaScriptCore/runtime/MachineStackMarker.h index e80fe05..8afdb46 100644 --- a/Source/JavaScriptCore/runtime/MachineStackMarker.h +++ b/Source/JavaScriptCore/runtime/MachineStackMarker.h @@ -32,14 +32,15 @@ namespace JSC { class Heap; - class MarkStack; + class ConservativeSet; - class MachineStackMarker : public Noncopyable { + class MachineStackMarker { + WTF_MAKE_NONCOPYABLE(MachineStackMarker); public: MachineStackMarker(Heap*); ~MachineStackMarker(); - void markMachineStackConservatively(MarkStack&); + void markMachineStackConservatively(ConservativeSet&); #if ENABLE(JSC_MULTIPLE_THREADS) void makeUsableFromMultipleThreads(); @@ -47,8 +48,8 @@ namespace JSC { #endif private: - void markCurrentThreadConservatively(MarkStack&); - void markCurrentThreadConservativelyInternal(MarkStack&); + void markCurrentThreadConservatively(ConservativeSet&); + void markCurrentThreadConservativelyInternal(ConservativeSet&); #if ENABLE(JSC_MULTIPLE_THREADS) class Thread; @@ -56,7 +57,7 @@ namespace JSC { static void unregisterThread(void*); void unregisterThread(); - void markOtherThreadConservatively(MarkStack&, Thread*); + void markOtherThreadConservatively(ConservativeSet&, Thread*); #endif Heap* m_heap; diff --git a/Source/JavaScriptCore/runtime/MarkStack.h b/Source/JavaScriptCore/runtime/MarkStack.h index 7bccadf..7946e65 100644 --- a/Source/JavaScriptCore/runtime/MarkStack.h +++ b/Source/JavaScriptCore/runtime/MarkStack.h @@ -27,6 +27,7 @@ #define MarkStack_h #include "JSValue.h" +#include <wtf/HashSet.h> #include <wtf/Noncopyable.h> #include <wtf/OSAllocator.h> @@ -37,7 +38,8 @@ namespace JSC { enum MarkSetProperties { MayContainNullValues, NoNullValues }; - class MarkStack : Noncopyable { + class MarkStack { + WTF_MAKE_NONCOPYABLE(MarkStack); public: MarkStack(void* jsArrayVPtr) : m_jsArrayVPtr(jsArrayVPtr) @@ -185,6 +187,20 @@ namespace JSC { bool m_isDraining; #endif }; + + class ConservativeSet { + public: + void add(JSCell* cell) { m_set.add(cell); } + void mark(MarkStack& markStack) + { + HashSet<JSCell*>::iterator end = m_set.end(); + for (HashSet<JSCell*>::iterator it = m_set.begin(); it != end; ++it) + markStack.append(*it); + } + + private: + HashSet<JSCell*> m_set; + }; } #endif diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.cpp b/Source/JavaScriptCore/runtime/MarkedSpace.cpp index 4bc3c18..036c8f0 100644 --- a/Source/JavaScriptCore/runtime/MarkedSpace.cpp +++ b/Source/JavaScriptCore/runtime/MarkedSpace.cpp @@ -108,8 +108,6 @@ NEVER_INLINE CollectorBlock* MarkedSpace::allocateBlock() NEVER_INLINE void MarkedSpace::freeBlock(size_t block) { - m_heap.didShrink = true; - ObjectIterator it(m_heap, block); ObjectIterator end(m_heap, block + 1); for ( ; it != end; ++it) @@ -162,8 +160,6 @@ void* MarkedSpace::allocate(size_t s) void MarkedSpace::resizeBlocks() { - m_heap.didShrink = false; - size_t usedCellCount = markedCells(); size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount); size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock; @@ -222,7 +218,7 @@ static inline bool isPossibleCell(void* p) return isCellAligned(p) && p; } -void MarkedSpace::markConservatively(MarkStack& markStack, void* start, void* end) +void MarkedSpace::markConservatively(ConservativeSet& conservativeSet, void* start, void* end) { #if OS(WINCE) if (start > end) { @@ -244,7 +240,6 @@ void MarkedSpace::markConservatively(MarkStack& markStack, void* start, void* en while (p != e) { char* x = *p++; if (isPossibleCell(x)) { - size_t usedBlocks; uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x); xAsBits &= CELL_ALIGN_MASK; @@ -254,11 +249,30 @@ void MarkedSpace::markConservatively(MarkStack& markStack, void* start, void* en continue; CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset); - usedBlocks = m_heap.usedBlocks; + size_t usedBlocks = m_heap.usedBlocks; for (size_t block = 0; block < usedBlocks; block++) { if (m_heap.collectorBlock(block) != blockAddr) continue; - markStack.append(reinterpret_cast<JSCell*>(xAsBits)); + + // x is a pointer into the heap. Now, verify that the cell it + // points to is live. (If the cell is dead, we must not mark it, + // since that would revive it in a zombie state.) + if (block < m_heap.nextBlock) { + conservativeSet.add(reinterpret_cast<JSCell*>(xAsBits)); + break; + } + + size_t cellOffset = offset / CELL_SIZE; + + if (block == m_heap.nextBlock && cellOffset < m_heap.nextCell) { + conservativeSet.add(reinterpret_cast<JSCell*>(xAsBits)); + break; + } + + if (blockAddr->marked.get(cellOffset)) { + conservativeSet.add(reinterpret_cast<JSCell*>(xAsBits)); + break; + } } } } diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.h b/Source/JavaScriptCore/runtime/MarkedSpace.h index 78f918c..af312b5 100644 --- a/Source/JavaScriptCore/runtime/MarkedSpace.h +++ b/Source/JavaScriptCore/runtime/MarkedSpace.h @@ -55,15 +55,14 @@ namespace JSC { size_t numBlocks; size_t usedBlocks; - bool didShrink; - CollectorBlock* collectorBlock(size_t index) const { return static_cast<CollectorBlock*>(blocks[index].base()); } }; - class MarkedSpace : public Noncopyable { + class MarkedSpace { + WTF_MAKE_NONCOPYABLE(MarkedSpace); public: MarkedSpace(JSGlobalData*); void destroy(ProtectCountSet&); @@ -86,7 +85,7 @@ namespace JSC { WeakGCHandle* addWeakGCHandle(JSCell*); - void markConservatively(MarkStack&, void* start, void* end); + void markConservatively(ConservativeSet&, void* start, void* end); static bool isNumber(JSCell*); @@ -114,8 +113,6 @@ namespace JSC { void markRoots(); - bool didShrink() { return m_heap.didShrink; } - private: CollectorHeap m_heap; JSGlobalData* m_globalData; diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index 58abde5..1714bd3 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -31,7 +31,9 @@ namespace JSC { class RegExpPrototype; struct RegExpConstructorPrivate; - struct RegExpConstructorPrivate : FastAllocBase { + struct RegExpConstructorPrivate { + WTF_MAKE_FAST_ALLOCATED; + public: // Global search cache / settings RegExpConstructorPrivate() : lastNumSubPatterns(0) diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 7fda5b1..b969e38 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -128,17 +128,6 @@ JSValue RegExpObject::exec(ExecState* exec) return jsNull(); } -static EncodedJSValue JSC_HOST_CALL callRegExpObject(ExecState* exec) -{ - return JSValue::encode(asRegExpObject(exec->callee())->exec(exec)); -} - -CallType RegExpObject::getCallData(CallData& callData) -{ - callData.native.function = callRegExpObject; - return CallTypeHost; -} - // Shared implementation used by test and exec. bool RegExpObject::match(ExecState* exec) { diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h index 19de929..99c84da 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.h +++ b/Source/JavaScriptCore/runtime/RegExpObject.h @@ -58,9 +58,9 @@ namespace JSC { private: bool match(ExecState*); - virtual CallType getCallData(CallData&); - - struct RegExpObjectData : FastAllocBase { + struct RegExpObjectData { + WTF_MAKE_FAST_ALLOCATED; + public: RegExpObjectData(NonNullPassRefPtr<RegExp> regExp, double lastIndex) : regExp(regExp) , lastIndex(lastIndex) @@ -70,7 +70,9 @@ namespace JSC { RefPtr<RegExp> regExp; double lastIndex; }; - +#if PLATFORM(WIN) + friend void WTF::deleteOwnedPtr<RegExpObjectData>(RegExpObjectData*); +#endif OwnPtr<RegExpObjectData> d; }; diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index 04bcc3b..a7c447d 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -34,6 +34,7 @@ #include "RegExpObject.h" #include "RegExp.h" #include "RegExpCache.h" +#include "StringRecursionChecker.h" #include "UStringConcatenate.h" namespace JSC { @@ -111,15 +112,21 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) return throwVMTypeError(exec); } + RegExpObject* thisObject = asRegExpObject(thisValue); + + StringRecursionChecker checker(exec, thisObject); + if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) + return earlyReturnValue; + char postfix[5] = { '/', 0, 0, 0, 0 }; int index = 1; - if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global).toBoolean(exec)) + if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec)) postfix[index++] = 'g'; - if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) + if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) postfix[index++] = 'i'; - if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline).toBoolean(exec)) + if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) postfix[index] = 'm'; - UString source = asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec); + UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec); // If source is empty, use "/(?:)/" to avoid colliding with comment syntax return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix)); } diff --git a/Source/JavaScriptCore/runtime/ScopeChain.h b/Source/JavaScriptCore/runtime/ScopeChain.h index 0b15b67..b104e75 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.h +++ b/Source/JavaScriptCore/runtime/ScopeChain.h @@ -21,7 +21,7 @@ #ifndef ScopeChain_h #define ScopeChain_h -#include "FastAllocBase.h" +#include <wtf/FastAllocBase.h> namespace JSC { @@ -31,7 +31,8 @@ namespace JSC { class MarkStack; class ScopeChainIterator; - class ScopeChainNode : public FastAllocBase { + class ScopeChainNode { + WTF_MAKE_FAST_ALLOCATED; public: ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) : next(next) diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp index f358727..5614932 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.cpp +++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp @@ -40,7 +40,8 @@ static inline bool isMarked(JSString* string) return string && Heap::isCellMarked(string); } -class SmallStringsStorage : public Noncopyable { +class SmallStringsStorage { + WTF_MAKE_NONCOPYABLE(SmallStringsStorage); WTF_MAKE_FAST_ALLOCATED; public: SmallStringsStorage(); diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index d1ebfb1..ac84fe8 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -37,7 +37,8 @@ namespace JSC { class MarkStack; class SmallStringsStorage; - class SmallStrings : public Noncopyable { + class SmallStrings { + WTF_MAKE_NONCOPYABLE(SmallStrings); WTF_MAKE_FAST_ALLOCATED; public: SmallStrings(); ~SmallStrings(); diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp new file mode 100644 index 0000000..4e74735 --- /dev/null +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "StringRecursionChecker.h" + +#include "Error.h" +#include "ExceptionHelpers.h" + +namespace JSC { + +EncodedJSValue StringRecursionChecker::throwStackOverflowError() +{ + return throwVMError(m_exec, createStackOverflowError(m_exec)); +} + +EncodedJSValue StringRecursionChecker::emptyString() +{ + return JSValue::encode(jsEmptyString(m_exec)); +} + +} diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h new file mode 100644 index 0000000..314f14e --- /dev/null +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef StringRecursionChecker_h +#define StringRecursionChecker_h + +#include "Interpreter.h" + +namespace JSC { + +class StringRecursionChecker { + WTF_MAKE_NONCOPYABLE(StringRecursionChecker); + +public: + StringRecursionChecker(ExecState*, JSObject* thisObject); + ~StringRecursionChecker(); + + EncodedJSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases + +private: + EncodedJSValue throwStackOverflowError(); + EncodedJSValue emptyString(); + EncodedJSValue performCheck(); + + ExecState* m_exec; + JSObject* m_thisObject; + EncodedJSValue m_earlyReturnValue; +}; + +inline EncodedJSValue StringRecursionChecker::performCheck() +{ + int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size(); + if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth) + return throwStackOverflowError(); + bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second; + if (alreadyVisited) + return emptyString(); // Return empty string to avoid infinite recursion. + return 0; // Indicate success. +} + +inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject) + : m_exec(exec) + , m_thisObject(thisObject) + , m_earlyReturnValue(performCheck()) +{ +} + +inline EncodedJSValue StringRecursionChecker::earlyReturnValue() const +{ + return m_earlyReturnValue; +} + +inline StringRecursionChecker::~StringRecursionChecker() +{ + if (m_earlyReturnValue) + return; + ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject)); + m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject); +} + +} + +#endif diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 1b1636d..2635501 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -122,6 +122,7 @@ namespace JSC { typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable; class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> { + WTF_MAKE_FAST_ALLOCATED; public: static PassRefPtr<SharedSymbolTable> create() { return adoptRef(new SharedSymbolTable); } private: diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index 2d4e59d..316794f 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -35,7 +35,8 @@ class JSCell; // A HashMap whose get() function returns emptyValue() for cells awaiting destruction. template<typename KeyType, typename MappedType> -class WeakGCMap : public FastAllocBase { +class WeakGCMap { + WTF_MAKE_FAST_ALLOCATED; /* Invariants: * A value enters the WeakGCMap marked. (Guaranteed by set().) diff --git a/Source/JavaScriptCore/runtime/WeakGCPtr.h b/Source/JavaScriptCore/runtime/WeakGCPtr.h index 6cc75a5..4946ee7 100644 --- a/Source/JavaScriptCore/runtime/WeakGCPtr.h +++ b/Source/JavaScriptCore/runtime/WeakGCPtr.h @@ -28,12 +28,12 @@ #include "Heap.h" #include "GCHandle.h" -#include <wtf/Noncopyable.h> namespace JSC { // A smart pointer whose get() function returns 0 for cells awaiting destruction. -template <typename T> class WeakGCPtr : Noncopyable { +template <typename T> class WeakGCPtr { + WTF_MAKE_NONCOPYABLE(WeakGCPtr); public: WeakGCPtr() : m_ptr(0) |