| /* |
| * Copyright (C) 2008, 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. |
| * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSGlobalData.h" |
| |
| #include "ArgList.h" |
| #include "CodeCache.h" |
| #include "CommonIdentifiers.h" |
| #include "DebuggerActivation.h" |
| #include "FunctionConstructor.h" |
| #include "GCActivityCallback.h" |
| #include "GetterSetter.h" |
| #include "Heap.h" |
| #include "HostCallReturnValue.h" |
| #include "IncrementalSweeper.h" |
| #include "Interpreter.h" |
| #include "JSActivation.h" |
| #include "JSAPIValueWrapper.h" |
| #include "JSArray.h" |
| #include "JSClassRef.h" |
| #include "JSFunction.h" |
| #include "JSLock.h" |
| #include "JSNameScope.h" |
| #include "JSNotAnObject.h" |
| #include "JSPropertyNameIterator.h" |
| #include "JSWithScope.h" |
| #include "Lexer.h" |
| #include "Lookup.h" |
| #include "Nodes.h" |
| #include "ParserArena.h" |
| #include "RegExpCache.h" |
| #include "RegExpObject.h" |
| #include "StrictEvalActivation.h" |
| #include "StrongInlines.h" |
| #include "UnlinkedCodeBlock.h" |
| #include <wtf/RetainPtr.h> |
| #include <wtf/Threading.h> |
| #include <wtf/WTFThreadData.h> |
| |
| #if ENABLE(DFG_JIT) |
| #include "ConservativeRoots.h" |
| #endif |
| |
| #if ENABLE(REGEXP_TRACING) |
| #include "RegExp.h" |
| #endif |
| |
| #if USE(CF) |
| #include <CoreFoundation/CoreFoundation.h> |
| #endif |
| |
| using namespace WTF; |
| |
| namespace JSC { |
| |
| extern const HashTable arrayConstructorTable; |
| extern const HashTable arrayPrototypeTable; |
| extern const HashTable booleanPrototypeTable; |
| extern const HashTable jsonTable; |
| extern const HashTable dateTable; |
| extern const HashTable dateConstructorTable; |
| extern const HashTable errorPrototypeTable; |
| extern const HashTable globalObjectTable; |
| extern const HashTable mathTable; |
| extern const HashTable numberConstructorTable; |
| extern const HashTable numberPrototypeTable; |
| JS_EXPORTDATA extern const HashTable objectConstructorTable; |
| extern const HashTable objectPrototypeTable; |
| extern const HashTable privateNamePrototypeTable; |
| extern const HashTable regExpTable; |
| extern const HashTable regExpConstructorTable; |
| extern const HashTable regExpPrototypeTable; |
| extern const HashTable stringTable; |
| extern const HashTable stringConstructorTable; |
| |
| // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either |
| // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below |
| // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind. |
| |
| #if ENABLE(ASSEMBLER) |
| static bool enableAssembler(ExecutableAllocator& executableAllocator) |
| { |
| if (!executableAllocator.isValid() || (!Options::useJIT() && !Options::useRegExpJIT())) |
| return false; |
| |
| #if USE(CF) |
| #if COMPILER(GCC) && !COMPILER(CLANG) |
| // FIXME: remove this once the EWS have been upgraded to LLVM. |
| // Work around a bug of GCC with strict-aliasing. |
| RetainPtr<CFStringRef> canUseJITKeyRetain(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); |
| CFStringRef canUseJITKey = canUseJITKeyRetain.get(); |
| #else |
| CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); |
| #endif // COMPILER(GCC) && !COMPILER(CLANG) |
| RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); |
| if (canUseJIT) |
| return kCFBooleanTrue == canUseJIT.get(); |
| #endif |
| |
| #if USE(CF) || OS(UNIX) |
| char* canUseJITString = getenv("JavaScriptCoreUseJIT"); |
| return !canUseJITString || atoi(canUseJITString); |
| #else |
| return true; |
| #endif |
| } |
| #endif // ENABLE(!ASSEMBLER) |
| |
| JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) |
| : |
| #if ENABLE(ASSEMBLER) |
| executableAllocator(*this), |
| #endif |
| heap(this, heapType) |
| , globalDataType(globalDataType) |
| , clientData(0) |
| , topCallFrame(CallFrame::noCaller()) |
| , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable)) |
| , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable)) |
| , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable)) |
| , dateTable(fastNew<HashTable>(JSC::dateTable)) |
| , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable)) |
| , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable)) |
| , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable)) |
| , jsonTable(fastNew<HashTable>(JSC::jsonTable)) |
| , mathTable(fastNew<HashTable>(JSC::mathTable)) |
| , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable)) |
| , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable)) |
| , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable)) |
| , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable)) |
| , privateNamePrototypeTable(fastNew<HashTable>(JSC::privateNamePrototypeTable)) |
| , regExpTable(fastNew<HashTable>(JSC::regExpTable)) |
| , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable)) |
| , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable)) |
| , stringTable(fastNew<HashTable>(JSC::stringTable)) |
| , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable)) |
| , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) |
| , propertyNames(new CommonIdentifiers(this)) |
| , emptyList(new MarkedArgumentBuffer) |
| , parserArena(adoptPtr(new ParserArena)) |
| , keywords(adoptPtr(new Keywords(this))) |
| , interpreter(0) |
| , jsArrayClassInfo(JSArray::s_classinfo()) |
| , jsFinalObjectClassInfo(JSFinalObject::s_classinfo()) |
| #if ENABLE(DFG_JIT) |
| , sizeOfLastScratchBuffer(0) |
| #endif |
| , dynamicGlobalObject(0) |
| , cachedUTCOffset(QNaN) |
| , m_enabledProfiler(0) |
| , m_regExpCache(new RegExpCache(this)) |
| #if ENABLE(REGEXP_TRACING) |
| , m_rtTraceList(new RTTraceList()) |
| #endif |
| #ifndef NDEBUG |
| , exclusiveThread(0) |
| #endif |
| #if CPU(X86) && ENABLE(JIT) |
| , m_timeoutCount(512) |
| #endif |
| , m_newStringsSinceLastHashConst(0) |
| #if ENABLE(ASSEMBLER) |
| , m_canUseAssembler(enableAssembler(executableAllocator)) |
| #endif |
| #if ENABLE(JIT) |
| , m_canUseJIT(m_canUseAssembler && Options::useJIT()) |
| #endif |
| #if ENABLE(YARR_JIT) |
| , m_canUseRegExpJIT(m_canUseAssembler && Options::useRegExpJIT()) |
| #endif |
| #if ENABLE(GC_VALIDATION) |
| , m_initializingObjectClass(0) |
| #endif |
| , m_inDefineOwnProperty(false) |
| , m_codeCache(CodeCache::create()) |
| { |
| interpreter = new Interpreter(*this); |
| |
| // Need to be careful to keep everything consistent here |
| JSLockHolder lock(this); |
| IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); |
| structureStructure.set(*this, Structure::createStructure(*this)); |
| debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull())); |
| interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull())); |
| terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull())); |
| stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull())); |
| notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull())); |
| propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull())); |
| getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull())); |
| apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull())); |
| JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull())); |
| executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull())); |
| nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull())); |
| evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull())); |
| programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull())); |
| functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull())); |
| regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull())); |
| sharedSymbolTableStructure.set(*this, SharedSymbolTable::createStructure(*this, 0, jsNull())); |
| structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); |
| sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); |
| withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); |
| unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); |
| unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); |
| unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull())); |
| unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull())); |
| |
| wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); |
| |
| #if ENABLE(JIT) |
| jitStubs = adoptPtr(new JITThunks(this)); |
| #endif |
| |
| 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(); |
| |
| LLInt::Data::performAssertions(*this); |
| |
| if (Options::enableProfiler()) |
| m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this)); |
| } |
| |
| JSGlobalData::~JSGlobalData() |
| { |
| // Clear this first to ensure that nobody tries to remove themselves from it. |
| m_perBytecodeProfiler.clear(); |
| |
| ASSERT(!m_apiLock.currentThreadIsHoldingLock()); |
| heap.didStartVMShutdown(); |
| |
| delete interpreter; |
| #ifndef NDEBUG |
| interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); |
| #endif |
| |
| arrayPrototypeTable->deleteTable(); |
| arrayConstructorTable->deleteTable(); |
| booleanPrototypeTable->deleteTable(); |
| dateTable->deleteTable(); |
| dateConstructorTable->deleteTable(); |
| errorPrototypeTable->deleteTable(); |
| globalObjectTable->deleteTable(); |
| jsonTable->deleteTable(); |
| mathTable->deleteTable(); |
| numberConstructorTable->deleteTable(); |
| numberPrototypeTable->deleteTable(); |
| objectConstructorTable->deleteTable(); |
| objectPrototypeTable->deleteTable(); |
| privateNamePrototypeTable->deleteTable(); |
| regExpTable->deleteTable(); |
| regExpConstructorTable->deleteTable(); |
| regExpPrototypeTable->deleteTable(); |
| stringTable->deleteTable(); |
| stringConstructorTable->deleteTable(); |
| |
| fastDelete(const_cast<HashTable*>(arrayConstructorTable)); |
| fastDelete(const_cast<HashTable*>(arrayPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(booleanPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(dateTable)); |
| fastDelete(const_cast<HashTable*>(dateConstructorTable)); |
| fastDelete(const_cast<HashTable*>(errorPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(globalObjectTable)); |
| fastDelete(const_cast<HashTable*>(jsonTable)); |
| fastDelete(const_cast<HashTable*>(mathTable)); |
| fastDelete(const_cast<HashTable*>(numberConstructorTable)); |
| fastDelete(const_cast<HashTable*>(numberPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(objectConstructorTable)); |
| fastDelete(const_cast<HashTable*>(objectPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(privateNamePrototypeTable)); |
| fastDelete(const_cast<HashTable*>(regExpTable)); |
| fastDelete(const_cast<HashTable*>(regExpConstructorTable)); |
| fastDelete(const_cast<HashTable*>(regExpPrototypeTable)); |
| fastDelete(const_cast<HashTable*>(stringTable)); |
| fastDelete(const_cast<HashTable*>(stringConstructorTable)); |
| |
| opaqueJSClassData.clear(); |
| |
| delete emptyList; |
| |
| delete propertyNames; |
| if (globalDataType != Default) |
| deleteIdentifierTable(identifierTable); |
| |
| delete clientData; |
| delete m_regExpCache; |
| #if ENABLE(REGEXP_TRACING) |
| delete m_rtTraceList; |
| #endif |
| |
| #if ENABLE(DFG_JIT) |
| for (unsigned i = 0; i < scratchBuffers.size(); ++i) |
| fastFree(scratchBuffers[i]); |
| #endif |
| } |
| |
| PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(HeapType heapType) |
| { |
| return adoptRef(new JSGlobalData(APIContextGroup, heapType)); |
| } |
| |
| PassRefPtr<JSGlobalData> JSGlobalData::create(HeapType heapType) |
| { |
| return adoptRef(new JSGlobalData(Default, heapType)); |
| } |
| |
| PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(HeapType heapType) |
| { |
| return create(heapType); |
| } |
| |
| bool JSGlobalData::sharedInstanceExists() |
| { |
| return sharedInstanceInternal(); |
| } |
| |
| #if !defined(__LB_SHELL__) && !OS(STARBOARD) |
| JSGlobalData& JSGlobalData::sharedInstance() |
| { |
| GlobalJSLock globalLock; |
| JSGlobalData*& instance = sharedInstanceInternal(); |
| if (!instance) { |
| instance = adoptRef(new JSGlobalData(APIShared, SmallHeap)).leakRef(); |
| instance->makeUsableFromMultipleThreads(); |
| } |
| return *instance; |
| } |
| #endif |
| |
| JSGlobalData*& JSGlobalData::sharedInstanceInternal() |
| { |
| static JSGlobalData* sharedInstance; |
| return sharedInstance; |
| } |
| |
| #if ENABLE(JIT) |
| static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) |
| { |
| switch (intrinsic) { |
| case CharCodeAtIntrinsic: |
| return charCodeAtThunkGenerator; |
| case CharAtIntrinsic: |
| return charAtThunkGenerator; |
| case FromCharCodeIntrinsic: |
| return fromCharCodeThunkGenerator; |
| case SqrtIntrinsic: |
| return sqrtThunkGenerator; |
| case PowIntrinsic: |
| return powThunkGenerator; |
| case AbsIntrinsic: |
| return absThunkGenerator; |
| case FloorIntrinsic: |
| return floorThunkGenerator; |
| case CeilIntrinsic: |
| return ceilThunkGenerator; |
| case RoundIntrinsic: |
| return roundThunkGenerator; |
| case ExpIntrinsic: |
| return expThunkGenerator; |
| case LogIntrinsic: |
| return logThunkGenerator; |
| default: |
| return 0; |
| } |
| } |
| |
| NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor) |
| { |
| return jitStubs->hostFunctionStub(this, function, constructor); |
| } |
| NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic) |
| { |
| ASSERT(canUseJIT()); |
| return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic); |
| } |
| |
| #else // !ENABLE(JIT) |
| NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor) |
| { |
| return NativeExecutable::create(*this, function, constructor); |
| } |
| #endif // !ENABLE(JIT) |
| |
| JSGlobalData::ClientData::~ClientData() |
| { |
| } |
| |
| void JSGlobalData::resetDateCache() |
| { |
| cachedUTCOffset = QNaN; |
| dstOffsetCache.reset(); |
| cachedDateString = String(); |
| cachedDateStringValue = QNaN; |
| dateInstanceCache.reset(); |
| } |
| |
| void JSGlobalData::startSampling() |
| { |
| interpreter->startSampling(); |
| } |
| |
| void JSGlobalData::stopSampling() |
| { |
| interpreter->stopSampling(); |
| } |
| |
| void JSGlobalData::discardAllCode() |
| { |
| m_codeCache->clear(); |
| heap.deleteAllCompiledCode(); |
| heap.reportAbandonedObjectGraph(); |
| } |
| |
| void JSGlobalData::dumpSampleData(ExecState* exec) |
| { |
| interpreter->dumpSampleData(exec); |
| #if ENABLE(ASSEMBLER) |
| ExecutableAllocator::dumpProfile(); |
| #endif |
| } |
| |
| struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { |
| HashSet<FunctionExecutable*> currentlyExecutingFunctions; |
| void operator()(JSCell* cell) |
| { |
| if (!cell->inherits(FunctionExecutable::s_classinfo())) |
| return; |
| FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); |
| if (currentlyExecutingFunctions.contains(executable)) |
| return; |
| executable->clearCodeIfNotCompiling(); |
| } |
| }; |
| |
| void JSGlobalData::releaseExecutableMemory() |
| { |
| if (dynamicGlobalObject) { |
| StackPreservingRecompiler recompiler; |
| HashSet<JSCell*> roots; |
| heap.getConservativeRegisterRoots(roots); |
| HashSet<JSCell*>::iterator end = roots.end(); |
| for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { |
| ScriptExecutable* executable = 0; |
| JSCell* cell = *ptr; |
| if (cell->inherits(ScriptExecutable::s_classinfo())) |
| executable = static_cast<ScriptExecutable*>(*ptr); |
| else if (cell->inherits(JSFunction::s_classinfo())) { |
| JSFunction* function = jsCast<JSFunction*>(*ptr); |
| if (function->isHostFunction()) |
| continue; |
| executable = function->jsExecutable(); |
| } else |
| continue; |
| ASSERT(executable->inherits(ScriptExecutable::s_classinfo())); |
| executable->unlinkCalls(); |
| if (executable->inherits(FunctionExecutable::s_classinfo())) |
| recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); |
| |
| } |
| heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(recompiler); |
| } |
| m_regExpCache->invalidateCode(); |
| heap.collectAllGarbage(); |
| } |
| |
| void releaseExecutableMemory(JSGlobalData& globalData) |
| { |
| globalData.releaseExecutableMemory(); |
| } |
| |
| #if ENABLE(DFG_JIT) |
| void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots) |
| { |
| for (size_t i = 0; i < scratchBuffers.size(); i++) { |
| ScratchBuffer* scratchBuffer = scratchBuffers[i]; |
| if (scratchBuffer->activeLength()) { |
| void* bufferStart = scratchBuffer->dataBuffer(); |
| conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength())); |
| } |
| } |
| } |
| #endif |
| |
| #if ENABLE(REGEXP_TRACING) |
| void JSGlobalData::addRegExpToTrace(RegExp* regExp) |
| { |
| m_rtTraceList->add(regExp); |
| } |
| |
| void JSGlobalData::dumpRegExpTrace() |
| { |
| // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used. |
| RTTraceList::iterator iter = ++m_rtTraceList->begin(); |
| |
| if (iter != m_rtTraceList->end()) { |
| dataLogF("\nRegExp Tracing\n"); |
| dataLogF(" match() matches\n"); |
| dataLogF("Regular Expression JIT Address calls found\n"); |
| dataLogF("----------------------------------------+----------------+----------+----------\n"); |
| |
| unsigned reCount = 0; |
| |
| for (; iter != m_rtTraceList->end(); ++iter, ++reCount) |
| (*iter)->printTraceData(); |
| |
| dataLogF("%d Regular Expressions\n", reCount); |
| } |
| |
| m_rtTraceList->clear(); |
| } |
| #else |
| void JSGlobalData::dumpRegExpTrace() |
| { |
| } |
| #endif |
| |
| } // namespace JSC |