]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/VM.cpp
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / runtime / VM.cpp
diff --git a/runtime/VM.cpp b/runtime/VM.cpp
new file mode 100644 (file)
index 0000000..33589b8
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 2008, 2011, 2013 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 "VM.h"
+
+#include "ArgList.h"
+#include "CodeCache.h"
+#include "CommonIdentifiers.h"
+#include "DFGLongLivedState.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 "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 "SourceProviderCache.h"
+#include "StrictEvalActivation.h"
+#include "StrongInlines.h"
+#include "UnlinkedCodeBlock.h"
+#include <wtf/ProcessID.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/StringPrintStream.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 privateNamePrototypeTable;
+extern const HashTable regExpTable;
+extern const HashTable regExpConstructorTable;
+extern const HashTable regExpPrototypeTable;
+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 (!Options::useJIT() && !Options::useRegExpJIT())
+        return false;
+
+    if (!executableAllocator.isValid()) {
+        if (Options::crashIfCantAllocateJITMemory())
+            CRASH();
+        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<CFTypeRef> canUseJIT = adoptCF(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)
+
+VM::VM(VMType vmType, HeapType heapType)
+    : m_apiLock(adoptRef(new JSLock(this)))
+#if ENABLE(ASSEMBLER)
+    , executableAllocator(*this)
+#endif
+    , heap(this, heapType)
+    , vmType(vmType)
+    , 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))
+    , privateNamePrototypeTable(fastNew<HashTable>(JSC::privateNamePrototypeTable))
+    , regExpTable(fastNew<HashTable>(JSC::regExpTable))
+    , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
+    , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
+    , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
+    , identifierTable(vmType == 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_info)
+    , jsFinalObjectClassInfo(&JSFinalObject::s_info)
+#if ENABLE(DFG_JIT)
+    , sizeOfLastScratchBuffer(0)
+#endif
+    , dynamicGlobalObject(0)
+    , m_enabledProfiler(0)
+    , m_regExpCache(new RegExpCache(this))
+#if ENABLE(REGEXP_TRACING)
+    , m_rtTraceList(new RTTraceList())
+#endif
+#ifndef NDEBUG
+    , exclusiveThread(0)
+#endif
+    , m_newStringsSinceLastHashCons(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(CodeCache::GlobalCodeCache))
+{
+    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));
+    structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
+    debuggerActivationStructure.set(*this, DebuggerActivation::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()));
+    propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
+    smallStrings.initializeCommonStrings(*this);
+
+    wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+
+#if ENABLE(JIT)
+    jitStubs = adoptPtr(new JITThunks());
+    performPlatformSpecificJITAssertions(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));
+
+        StringPrintStream pathOut;
+#if !OS(WINCE)
+        const char* profilerPath = getenv("JSC_PROFILER_PATH");
+        if (profilerPath)
+            pathOut.print(profilerPath, "/");
+#endif
+        pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json");
+        m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data());
+    }
+
+#if ENABLE(DFG_JIT)
+    if (canUseJIT())
+        m_dfgState = adoptPtr(new DFG::LongLivedState());
+#endif
+}
+
+VM::~VM()
+{
+    // Clear this first to ensure that nobody tries to remove themselves from it.
+    m_perBytecodeProfiler.clear();
+    
+    ASSERT(m_apiLock->currentThreadIsHoldingLock());
+    m_apiLock->willDestroyVM(this);
+    heap.lastChanceToFinalize();
+
+    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();
+    privateNamePrototypeTable->deleteTable();
+    regExpTable->deleteTable();
+    regExpConstructorTable->deleteTable();
+    regExpPrototypeTable->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*>(privateNamePrototypeTable));
+    fastDelete(const_cast<HashTable*>(regExpTable));
+    fastDelete(const_cast<HashTable*>(regExpConstructorTable));
+    fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
+    fastDelete(const_cast<HashTable*>(stringConstructorTable));
+
+    delete emptyList;
+
+    delete propertyNames;
+    if (vmType != 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<VM> VM::createContextGroup(HeapType heapType)
+{
+    return adoptRef(new VM(APIContextGroup, heapType));
+}
+
+PassRefPtr<VM> VM::create(HeapType heapType)
+{
+    return adoptRef(new VM(Default, heapType));
+}
+
+PassRefPtr<VM> VM::createLeaked(HeapType heapType)
+{
+    return create(heapType);
+}
+
+bool VM::sharedInstanceExists()
+{
+    return sharedInstanceInternal();
+}
+
+VM& VM::sharedInstance()
+{
+    GlobalJSLock globalLock;
+    VM*& instance = sharedInstanceInternal();
+    if (!instance) {
+        instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef();
+        instance->makeUsableFromMultipleThreads();
+    }
+    return *instance;
+}
+
+VM*& VM::sharedInstanceInternal()
+{
+    static VM* 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;
+    case IMulIntrinsic:
+        return imulThunkGenerator;
+    default:
+        return 0;
+    }
+}
+
+NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+    return jitStubs->hostFunctionStub(this, function, constructor);
+}
+NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic)
+{
+    ASSERT(canUseJIT());
+    return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
+}
+
+#else // !ENABLE(JIT)
+NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+    return NativeExecutable::create(*this, function, constructor);
+}
+#endif // !ENABLE(JIT)
+
+VM::ClientData::~ClientData()
+{
+}
+
+void VM::resetDateCache()
+{
+    localTimeOffsetCache.reset();
+    cachedDateString = String();
+    cachedDateStringValue = QNaN;
+    dateInstanceCache.reset();
+}
+
+void VM::startSampling()
+{
+    interpreter->startSampling();
+}
+
+void VM::stopSampling()
+{
+    interpreter->stopSampling();
+}
+
+void VM::discardAllCode()
+{
+    m_codeCache->clear();
+    heap.deleteAllCompiledCode();
+    heap.reportAbandonedObjectGraph();
+}
+
+void VM::dumpSampleData(ExecState* exec)
+{
+    interpreter->dumpSampleData(exec);
+#if ENABLE(ASSEMBLER)
+    ExecutableAllocator::dumpProfile();
+#endif
+}
+
+SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider)
+{
+    SourceProviderCacheMap::AddResult addResult = sourceProviderCacheMap.add(sourceProvider, 0);
+    if (addResult.isNewEntry)
+        addResult.iterator->value = adoptRef(new SourceProviderCache);
+    return addResult.iterator->value.get();
+}
+
+void VM::clearSourceProviderCaches()
+{
+    sourceProviderCacheMap.clear();
+}
+
+struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
+    HashSet<FunctionExecutable*> currentlyExecutingFunctions;
+    void operator()(JSCell* cell)
+    {
+        if (!cell->inherits(&FunctionExecutable::s_info))
+            return;
+        FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
+        if (currentlyExecutingFunctions.contains(executable))
+            return;
+        executable->clearCodeIfNotCompiling();
+    }
+};
+
+void VM::releaseExecutableMemory()
+{
+    if (dynamicGlobalObject) {
+        StackPreservingRecompiler recompiler;
+        HashSet<JSCell*> roots;
+        heap.canonicalizeCellLivenessData();
+        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_info))
+                executable = static_cast<ScriptExecutable*>(*ptr);
+            else if (cell->inherits(&JSFunction::s_info)) {
+                JSFunction* function = jsCast<JSFunction*>(*ptr);
+                if (function->isHostFunction())
+                    continue;
+                executable = function->jsExecutable();
+            } else
+                continue;
+            ASSERT(executable->inherits(&ScriptExecutable::s_info));
+            executable->unlinkCalls();
+            if (executable->inherits(&FunctionExecutable::s_info))
+                recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
+                
+        }
+        heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(recompiler);
+    }
+    m_regExpCache->invalidateCode();
+    heap.collectAllGarbage();
+}
+
+void VM::clearExceptionStack()
+{
+    m_exceptionStack = RefCountedArray<StackFrame>();
+}
+    
+#if ENABLE(ASSEMBLER)
+void releaseExecutableMemory(VM& vm)
+{
+    vm.releaseExecutableMemory();
+}
+#endif
+
+#if ENABLE(DFG_JIT)
+void VM::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 VM::addRegExpToTrace(RegExp* regExp)
+{
+    m_rtTraceList->add(regExp);
+}
+
+void VM::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 VM::dumpRegExpTrace()
+{
+}
+#endif
+
+} // namespace JSC