/*
- * 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 "GCActivityCallback.h"
+#include "GetterSetter.h"
+#include "HostCallReturnValue.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 "Lexer.h"
#include "Lookup.h"
#include "Nodes.h"
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#include "ParserArena.h"
+#include "RegExpCache.h"
+#include "RegExpObject.h"
+#include "StrictEvalActivation.h"
+#include "StrongInlines.h"
#include <wtf/Threading.h>
+#include <wtf/WTFThreadData.h>
+
+#if ENABLE(DFG_JIT)
+#include "ConservativeRoots.h"
#endif
-#if PLATFORM(MAC)
-#include "ProfilerServer.h"
+#if ENABLE(REGEXP_TRACING)
+#include "RegExp.h"
+#endif
+
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
#endif
using namespace WTF;
namespace JSC {
-extern JSC_CONST_HASHTABLE HashTable arrayTable;
-extern JSC_CONST_HASHTABLE HashTable jsonTable;
-extern JSC_CONST_HASHTABLE HashTable dateTable;
-extern JSC_CONST_HASHTABLE HashTable mathTable;
-extern JSC_CONST_HASHTABLE HashTable numberTable;
-extern JSC_CONST_HASHTABLE HashTable regExpTable;
-extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
-extern JSC_CONST_HASHTABLE HashTable stringTable;
-
-struct VPtrSet {
- VPtrSet();
-
- void* jsArrayVPtr;
- void* jsByteArrayVPtr;
- void* jsStringVPtr;
- void* jsFunctionVPtr;
-};
-
-VPtrSet::VPtrSet()
+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 regExpTable;
+extern const HashTable regExpConstructorTable;
+extern const HashTable regExpPrototypeTable;
+extern const HashTable stringTable;
+extern const HashTable stringConstructorTable;
+
+#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
+static bool enableAssembler(ExecutableAllocator& executableAllocator)
{
- // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
- void* storage = fastMalloc(sizeof(CollectorBlock));
-
- JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
- jsArrayVPtr = jsArray->vptr();
- jsArray->~JSCell();
-
- JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
- jsByteArrayVPtr = jsByteArray->vptr();
- jsByteArray->~JSCell();
-
- JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
- jsStringVPtr = jsString->vptr();
- jsString->~JSCell();
-
- JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
- jsFunctionVPtr = jsFunction->vptr();
- jsFunction->~JSCell();
+ if (!executableAllocator.isValid() || !Options::useJIT)
+ return false;
+#if USE(CF)
+ CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
+ CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
+ if (canUseJIT) {
+ return kCFBooleanTrue == canUseJIT;
+ CFRelease(canUseJIT);
+ }
+ CFRelease(canUseJITKey);
+#endif
- fastFree(storage);
+#if USE(CF) || OS(UNIX)
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ return !canUseJITString || atoi(canUseJITString);
+#else
+ return true;
+#endif
}
+#endif
-JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
- : isSharedInstance(isShared)
+JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize)
+ : heap(this, heapSize)
+ , globalDataType(globalDataType)
, clientData(0)
- , arrayTable(fastNew<HashTable>(JSC::arrayTable))
+ , 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))
- , numberTable(fastNew<HashTable>(JSC::numberTable))
+ , 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))
- , 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(JSVALUE32)
- , numberStructure(JSNumberCell::createStructure(jsNull()))
-#endif
- , jsArrayVPtr(vptrSet.jsArrayVPtr)
- , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr)
- , jsStringVPtr(vptrSet.jsStringVPtr)
- , jsFunctionVPtr(vptrSet.jsFunctionVPtr)
- , identifierTable(createIdentifierTable())
+ , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
+ , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
, emptyList(new MarkedArgumentBuffer)
- , lexer(new Lexer(this))
- , parser(new Parser)
- , interpreter(new Interpreter)
-#if ENABLE(JIT)
- , jitStubs(this)
+#if ENABLE(ASSEMBLER)
+ , executableAllocator(*this)
+#endif
+ , 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
- , heap(this)
- , initializingLazyNumericCompareFunction(false)
- , head(0)
, dynamicGlobalObject(0)
- , scopeNodeBeingReparsed(0)
- , firstStringifierToMark(0)
+ , cachedUTCOffset(std::numeric_limits<double>::quiet_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
+#if CPU(X86) && ENABLE(JIT)
+ , m_timeoutCount(512)
+#endif
+#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
+ , m_canUseAssembler(enableAssembler(executableAllocator))
+#endif
+#if ENABLE(GC_VALIDATION)
+ , m_initializingObjectClass(0)
+#endif
+ , m_inDefineOwnProperty(false)
{
-#if PLATFORM(MAC)
- startProfilerServerIfNeeded();
+ interpreter = new Interpreter;
+
+ // 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()));
+ activationStructure.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
+ interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
+ terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
+ staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
+ strictEvalActivationStructure.set(*this, StrictEvalActivation::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()));
+ scopeChainNodeStructure.set(*this, ScopeChainNode::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()));
+ structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
+
+ wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+
+#if ENABLE(JIT)
+ jitStubs = adoptPtr(new JITThunks(this));
#endif
+
+ interpreter->initialize(&llintData, this->canUseJIT());
+
+ initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
+
+ heap.notifyIsSafeToCollect();
+
+ llintData.performAssertions(*this);
}
JSGlobalData::~JSGlobalData()
{
- // By the time this is destroyed, heap.destroy() must already have been called.
+ ASSERT(!m_apiLock.currentThreadIsHoldingLock());
+ if (heap.activityCallback())
+ heap.activityCallback()->didStartVMShutdown();
+ heap.lastChanceToFinalize();
delete interpreter;
#ifndef NDEBUG
- // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
- interpreter = 0;
+ interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
#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();
+ stringConstructorTable->deleteTable();
- fastDelete(const_cast<HashTable*>(arrayTable));
+ 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*>(numberTable));
+ 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;
-
- deleteAllValues(opaqueJSClassData);
+ opaqueJSClassData.clear();
delete emptyList;
delete propertyNames;
- deleteIdentifierTable(identifierTable);
+ 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(ThreadStackType type, HeapSize heapSize)
+{
+ return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize));
}
-PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared)
+PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapSize heapSize)
{
- return adoptRef(new JSGlobalData(isShared, VPtrSet()));
+ return adoptRef(new JSGlobalData(Default, type, heapSize));
}
-PassRefPtr<JSGlobalData> JSGlobalData::createLeaked()
+PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize)
{
- Structure::startIgnoringLeaks();
- RefPtr<JSGlobalData> data = create();
- Structure::stopIgnoringLeaks();
- return data.release();
+ return create(type, heapSize);
}
bool JSGlobalData::sharedInstanceExists()
JSGlobalData& JSGlobalData::sharedInstance()
{
+ GlobalJSLock globalLock;
JSGlobalData*& instance = sharedInstanceInternal();
if (!instance) {
- instance = create(true).releaseRef();
-#if ENABLE(JSC_MULTIPLE_THREADS)
+ instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
instance->makeUsableFromMultipleThreads();
-#endif
}
return *instance;
}
JSGlobalData*& JSGlobalData::sharedInstanceInternal()
{
- ASSERT(JSLock::currentThreadIsHoldingLock());
static JSGlobalData* sharedInstance;
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)
+static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
{
- 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;
+ 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;
}
+}
- return lazyNumericCompareFunction;
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+#if ENABLE(CLASSIC_INTERPRETER)
+ if (!canUseJIT())
+ return NativeExecutable::create(*this, function, constructor);
+#endif
+ 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
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+ return NativeExecutable::create(*this, function, constructor);
}
+#endif
JSGlobalData::ClientData::~ClientData()
{
}
+void JSGlobalData::resetDateCache()
+{
+ cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
+ dstOffsetCache.reset();
+ cachedDateString = UString();
+ cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
+ dateInstanceCache.reset();
+}
+
+void JSGlobalData::startSampling()
+{
+ interpreter->startSampling();
+}
+
+void JSGlobalData::stopSampling()
+{
+ interpreter->stopSampling();
+}
+
+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_info))
+ return;
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
+ if (currentlyExecutingFunctions.contains(executable))
+ return;
+ executable->discardCode();
+ }
+};
+
+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 = 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().forEachCell<StackPreservingRecompiler>(recompiler);
+ }
+ m_regExpCache->invalidateCode();
+ heap.collectAllGarbage();
+}
+
+#if ENABLE(ASSEMBLER)
+void releaseExecutableMemory(JSGlobalData& globalData)
+{
+ globalData.releaseExecutableMemory();
+}
+#endif
+
+#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()) {
+ dataLog("\nRegExp Tracing\n");
+ dataLog(" match() matches\n");
+ dataLog("Regular Expression JIT Address calls found\n");
+ dataLog("----------------------------------------+----------------+----------+----------\n");
+
+ unsigned reCount = 0;
+
+ for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
+ (*iter)->printTraceData();
+
+ dataLog("%d Regular Expressions\n", reCount);
+ }
+
+ m_rtTraceList->clear();
+}
+#else
+void JSGlobalData::dumpRegExpTrace()
+{
+}
+#endif
+
} // namespace JSC