]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSGlobalData.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / runtime / JSGlobalData.cpp
index 10b584d9a8d3e2dcef14ca3ff17e3ac97866f0be..377e849154dce5a33032ae9638b4a6ffd310d25d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * 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
 #include "JSGlobalData.h"
 
 #include "ArgList.h"
-#include "Collector.h"
+#include "Heap.h"
 #include "CommonIdentifiers.h"
+#include "DebuggerActivation.h"
 #include "FunctionConstructor.h"
+#include "GetterSetter.h"
 #include "Interpreter.h"
 #include "JSActivation.h"
+#include "JSAPIValueWrapper.h"
+#include "JSArray.h"
+#include "JSByteArray.h"
 #include "JSClassRef.h"
+#include "JSFunction.h"
 #include "JSLock.h"
 #include "JSNotAnObject.h"
+#include "JSPropertyNameIterator.h"
 #include "JSStaticScopeObject.h"
-#include "Parser.h"
+#include "JSZombie.h"
 #include "Lexer.h"
 #include "Lookup.h"
 #include "Nodes.h"
+#include "Parser.h"
+#include "RegExpCache.h"
+#include "RegExpObject.h"
+#include "StrictEvalActivation.h"
+#include <wtf/WTFThreadData.h>
+#if ENABLE(REGEXP_TRACING)
+#include "RegExp.h"
+#endif
+
 
 #if ENABLE(JSC_MULTIPLE_THREADS)
 #include <wtf/Threading.h>
 
 #if PLATFORM(MAC)
 #include "ProfilerServer.h"
+#include <CoreFoundation/CoreFoundation.h>
 #endif
 
 using namespace WTF;
 
+namespace {
+
+using namespace JSC;
+
+class Recompiler {
+public:
+    void operator()(JSCell*);
+};
+
+inline void Recompiler::operator()(JSCell* cell)
+{
+    if (!cell->inherits(&JSFunction::s_info))
+        return;
+    JSFunction* function = asFunction(cell);
+    if (function->executable()->isHostFunction())
+        return;
+    function->jsExecutable()->discardCode();
+}
+
+} // namespace
+
 namespace JSC {
 
-extern const HashTable arrayTable;
-extern const HashTable dateTable;
-extern const HashTable mathTable;
-extern const HashTable numberTable;
-extern const HashTable regExpTable;
-extern const HashTable regExpConstructorTable;
-extern const HashTable stringTable;
-
-JSGlobalData::JSGlobalData(bool isShared)
-    : initializingLazyNumericCompareFunction(false)
-    , interpreter(new Interpreter)
-    , exception(noValue())
-    , arrayTable(new HashTable(JSC::arrayTable))
-    , dateTable(new HashTable(JSC::dateTable))
-    , mathTable(new HashTable(JSC::mathTable))
-    , numberTable(new HashTable(JSC::numberTable))
-    , regExpTable(new HashTable(JSC::regExpTable))
-    , regExpConstructorTable(new HashTable(JSC::regExpConstructorTable))
-    , stringTable(new HashTable(JSC::stringTable))
-    , activationStructure(JSActivation::createStructure(jsNull()))
-    , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull()))
-    , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
-    , stringStructure(JSString::createStructure(jsNull()))
-    , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull()))
-    , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
-#if !USE(ALTERNATE_JSIMMEDIATE)
-    , numberStructure(JSNumberCell::createStructure(jsNull()))
-#endif
-    , identifierTable(createIdentifierTable())
+extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable jsonTable;
+extern JSC_CONST_HASHTABLE HashTable dateTable;
+extern JSC_CONST_HASHTABLE HashTable dateConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable globalObjectTable;
+extern JSC_CONST_HASHTABLE HashTable mathTable;
+extern JSC_CONST_HASHTABLE HashTable numberConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable objectConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable regExpTable;
+extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable stringTable;
+extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
+
+void* JSGlobalData::jsArrayVPtr;
+void* JSGlobalData::jsByteArrayVPtr;
+void* JSGlobalData::jsStringVPtr;
+void* JSGlobalData::jsFunctionVPtr;
+
+#if COMPILER(GCC)
+// Work around for gcc trying to coalesce our reads of the various cell vptrs
+#define CLOBBER_MEMORY() do { \
+    asm volatile ("" : : : "memory"); \
+} while (false)
+#else
+#define CLOBBER_MEMORY() do { } while (false)
+#endif
+
+void JSGlobalData::storeVPtrs()
+{
+    // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
+    // COMPILE_ASSERTS below check that this is true.
+    char storage[64];
+
+    COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
+    JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
+    CLOBBER_MEMORY();
+    JSGlobalData::jsArrayVPtr = jsArray->vptr();
+
+    COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
+    JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
+    CLOBBER_MEMORY();
+    JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
+
+    COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
+    JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
+    CLOBBER_MEMORY();
+    JSGlobalData::jsStringVPtr = jsString->vptr();
+
+    COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
+    JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack);
+    CLOBBER_MEMORY();
+    JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
+}
+
+JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
+    : globalDataType(globalDataType)
+    , clientData(0)
+    , 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))
+    , 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 ArgList)
-    , newParserObjects(0)
-    , parserObjectExtraRefCounts(0)
+    , emptyList(new MarkedArgumentBuffer)
+#if ENABLE(ASSEMBLER)
+    , executableAllocator(*this)
+    , regexAllocator(*this)
+#endif
     , lexer(new Lexer(this))
     , parser(new Parser)
-    , head(0)
-    , dynamicGlobalObject(0)
-    , isSharedInstance(isShared)
-    , clientData(0)
-    , scopeNodeBeingReparsed(0)
+    , interpreter(0)
     , heap(this)
+    , globalObjectCount(0)
+    , dynamicGlobalObject(0)
+    , cachedUTCOffset(NaN)
+    , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
+    , m_regExpCache(new RegExpCache(this))
+#if ENABLE(REGEXP_TRACING)
+    , m_rtTraceList(new RTTraceList())
+#endif
+#ifndef NDEBUG
+    , exclusiveThread(0)
+#endif
 {
+    interpreter = new Interpreter(*this);
+    if (globalDataType == Default)
+        m_stack = wtfThreadData().stack();
+
+    // Need to be careful to keep everything consistent here
+    IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
+    JSLock lock(SilenceAssertionsOnly);
+    structureStructure.set(*this, Structure::createStructure(*this));
+    debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, jsNull()));
+    activationStructure.set(*this, JSActivation::createStructure(*this, jsNull()));
+    interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
+    terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
+    staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull()));
+    strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull()));
+    stringStructure.set(*this, JSString::createStructure(*this, jsNull()));
+    notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull()));
+    propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull()));
+    getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull()));
+    apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull()));
+    scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull()));
+    executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull()));
+    nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull()));
+    evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull()));
+    programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull()));
+    functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull()));
+    dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this));
+    regExpStructure.set(*this, RegExp::createStructure(*this, jsNull()));
+    structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull()));
+
+#if ENABLE(JSC_ZOMBIES)
+    zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull()));
+#endif
+
+    wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+
 #if PLATFORM(MAC)
     startProfilerServerIfNeeded();
 #endif
-    interpreter->initialize(this);
+#if ENABLE(JIT) && ENABLE(INTERPRETER)
+#if USE(CF)
+    CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
+    CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
+    if (canUseJIT) {
+        m_canUseJIT = kCFBooleanTrue == canUseJIT;
+        CFRelease(canUseJIT);
+    } else {
+      char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+      m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+    }
+    CFRelease(canUseJITKey);
+#elif OS(UNIX)
+    char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+    m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+#else
+    m_canUseJIT = true;
+#endif
+#endif
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+    if (m_canUseJIT)
+        m_canUseJIT = executableAllocator.isValid();
+#endif
+    jitStubs = adoptPtr(new JITThunks(this));
+#endif
+}
+
+void JSGlobalData::clearBuiltinStructures()
+{
+    structureStructure.clear();
+    debuggerActivationStructure.clear();
+    activationStructure.clear();
+    interruptedExecutionErrorStructure.clear();
+    terminatedExecutionErrorStructure.clear();
+    staticScopeStructure.clear();
+    strictEvalActivationStructure.clear();
+    stringStructure.clear();
+    notAnObjectStructure.clear();
+    propertyNameIteratorStructure.clear();
+    getterSetterStructure.clear();
+    apiWrapperStructure.clear();
+    scopeChainNodeStructure.clear();
+    executableStructure.clear();
+    nativeExecutableStructure.clear();
+    evalExecutableStructure.clear();
+    programExecutableStructure.clear();
+    functionExecutableStructure.clear();
+    dummyMarkableCellStructure.clear();
+    regExpStructure.clear();
+    structureChainStructure.clear();
+
+#if ENABLE(JSC_ZOMBIES)
+    zombieStructure.clear();
+#endif
 }
 
 JSGlobalData::~JSGlobalData()
@@ -114,20 +303,43 @@ JSGlobalData::~JSGlobalData()
     interpreter = 0;
 #endif
 
-    arrayTable->deleteTable();
+    arrayPrototypeTable->deleteTable();
+    arrayConstructorTable->deleteTable();
+    booleanPrototypeTable->deleteTable();
     dateTable->deleteTable();
+    dateConstructorTable->deleteTable();
+    errorPrototypeTable->deleteTable();
+    globalObjectTable->deleteTable();
+    jsonTable->deleteTable();
     mathTable->deleteTable();
-    numberTable->deleteTable();
+    numberConstructorTable->deleteTable();
+    numberPrototypeTable->deleteTable();
+    objectConstructorTable->deleteTable();
+    objectPrototypeTable->deleteTable();
     regExpTable->deleteTable();
     regExpConstructorTable->deleteTable();
+    regExpPrototypeTable->deleteTable();
     stringTable->deleteTable();
-    delete arrayTable;
-    delete dateTable;
-    delete mathTable;
-    delete numberTable;
-    delete regExpTable;
-    delete regExpConstructorTable;
-    delete stringTable;
+    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*>(regExpTable));
+    fastDelete(const_cast<HashTable*>(regExpConstructorTable));
+    fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
+    fastDelete(const_cast<HashTable*>(stringTable));
+    fastDelete(const_cast<HashTable*>(stringConstructorTable));
 
     delete parser;
     delete lexer;
@@ -137,29 +349,29 @@ JSGlobalData::~JSGlobalData()
     delete emptyList;
 
     delete propertyNames;
-    deleteIdentifierTable(identifierTable);
+    if (globalDataType != Default)
+        deleteIdentifierTable(identifierTable);
 
-    delete newParserObjects;
-    delete parserObjectExtraRefCounts;
-    
     delete clientData;
+    delete m_regExpCache;
+#if ENABLE(REGEXP_TRACING)
+    delete m_rtTraceList;
+#endif
 }
 
-PassRefPtr<JSGlobalData> JSGlobalData::create()
+PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
 {
-    return adoptRef(new JSGlobalData);
+    return adoptRef(new JSGlobalData(APIContextGroup, type));
 }
 
-PassRefPtr<JSGlobalData> JSGlobalData::createLeaked()
+PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type)
 {
-#ifndef NDEBUG
-    Structure::startIgnoringLeaks();
-    RefPtr<JSGlobalData> data = create();
-    Structure::stopIgnoringLeaks();
-    return data.release();
-#else
-    return create();
-#endif
+    return adoptRef(new JSGlobalData(Default, type));
+}
+
+PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
+{
+    return create(type);
 }
 
 bool JSGlobalData::sharedInstanceExists()
@@ -171,7 +383,7 @@ JSGlobalData& JSGlobalData::sharedInstance()
 {
     JSGlobalData*& instance = sharedInstanceInternal();
     if (!instance) {
-        instance = new JSGlobalData(true);
+        instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
 #if ENABLE(JSC_MULTIPLE_THREADS)
         instance->makeUsableFromMultipleThreads();
 #endif
@@ -186,22 +398,144 @@ JSGlobalData*& JSGlobalData::sharedInstanceInternal()
     return sharedInstance;
 }
 
-// FIXME: We can also detect forms like v1 < v2 ? -1 : 0, reverse comparison, etc.
-const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec)
+#if ENABLE(JIT)
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
+{
+    return jitStubs->hostFunctionStub(this, function);
+}
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
+{
+    return jitStubs->hostFunctionStub(this, function, generator);
+}
+#else
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
+{
+    return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
+}
+#endif
+
+JSGlobalData::ClientData::~ClientData()
+{
+}
+
+void JSGlobalData::resetDateCache()
+{
+    cachedUTCOffset = NaN;
+    dstOffsetCache.reset();
+    cachedDateString = UString();
+    cachedDateStringValue = NaN;
+    dateInstanceCache.reset();
+}
+
+void JSGlobalData::startSampling()
+{
+    interpreter->startSampling();
+}
+
+void JSGlobalData::stopSampling()
+{
+    interpreter->stopSampling();
+}
+
+void JSGlobalData::dumpSampleData(ExecState* exec)
 {
-    if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) {
-        initializingLazyNumericCompareFunction = true;
-        RefPtr<ProgramNode> programNode = parser->parse<ProgramNode>(exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0);
-        RefPtr<FunctionBodyNode> functionBody = extractFunctionBody(programNode.get());
-        lazyNumericCompareFunction = functionBody->bytecode(exec->scopeChain()).instructions();
-        initializingLazyNumericCompareFunction = false;
+    interpreter->dumpSampleData(exec);
+}
+
+void JSGlobalData::recompileAllJSFunctions()
+{
+    // If JavaScript is running, it's not safe to recompile, since we'll end
+    // up throwing away code that is live on the stack.
+    ASSERT(!dynamicGlobalObject);
+    
+    Recompiler recompiler;
+    heap.forEach(recompiler);
+}
+
+struct StackPreservingRecompiler {
+    HashSet<FunctionExecutable*> currentlyExecutingFunctions;
+    void operator()(JSCell* cell)
+    {
+        if (!cell->inherits(&FunctionExecutable::s_info))
+            return;
+        FunctionExecutable* executable = static_cast<FunctionExecutable*>(cell);
+        if (currentlyExecutingFunctions.contains(executable))
+            return;
+        executable->discardCode();
     }
+};
 
-    return lazyNumericCompareFunction;
+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_info))
+                executable = static_cast<ScriptExecutable*>(*ptr);
+            else if (cell->inherits(&JSFunction::s_info)) {
+                JSFunction* function = asFunction(*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.forEach(recompiler);
+    } else
+        recompileAllJSFunctions();
+
+    m_regExpCache->invalidateCode();
+    heap.collectAllGarbage();
 }
 
-JSGlobalData::ClientData::~ClientData()
+#if ENABLE(ASSEMBLER)
+void releaseExecutableMemory(JSGlobalData& globalData)
+{
+    globalData.releaseExecutableMemory();
+}
+#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()) {
+        printf("\nRegExp Tracing\n");
+        printf("                                                            match()    matches\n");
+        printf("Regular Expression                          JIT Address      calls      found\n");
+        printf("----------------------------------------+----------------+----------+----------\n");
+    
+        unsigned reCount = 0;
+    
+        for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
+            (*iter)->printTraceData();
+
+        printf("%d Regular Expressions\n", reCount);
+    }
+    
+    m_rtTraceList->clear();
+}
+#else
+void JSGlobalData::dumpRegExpTrace()
+{
+}
+#endif
+
 } // namespace JSC