X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b80e619319b1def83d1e8b4f84042b661be1be7f..1981f5dfe8d77d97469d20652f712a09400c48ed:/runtime/JSGlobalData.cpp diff --git a/runtime/JSGlobalData.cpp b/runtime/JSGlobalData.cpp index 41b841e..31ba6b4 100644 --- a/runtime/JSGlobalData.cpp +++ b/runtime/JSGlobalData.cpp @@ -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 @@ -30,16 +30,17 @@ #include "JSGlobalData.h" #include "ArgList.h" -#include "Collector.h" -#include "CollectorHeapIterator.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" @@ -49,16 +50,23 @@ #include "Lexer.h" #include "Lookup.h" #include "Nodes.h" -#include "Parser.h" +#include "ParserArena.h" #include "RegExpCache.h" +#include "RegExpObject.h" +#include "StrictEvalActivation.h" +#include "StrongInlines.h" +#include #include -#if ENABLE(JSC_MULTIPLE_THREADS) -#include +#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 #endif @@ -66,151 +74,199 @@ 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; - -void* JSGlobalData::jsArrayVPtr; -void* JSGlobalData::jsByteArrayVPtr; -void* JSGlobalData::jsStringVPtr; -void* JSGlobalData::jsFunctionVPtr; - -void JSGlobalData::storeVPtrs() +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) { - CollectorCell cell; - void* storage = &cell; - - COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell); - JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); - JSGlobalData::jsArrayVPtr = jsArray->vptr(); - jsArray->~JSCell(); - - COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell); - JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); - JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); - jsByteArray->~JSCell(); - - COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell); - JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); - JSGlobalData::jsStringVPtr = jsString->vptr(); - jsString->~JSCell(); - - COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell); - JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); - JSGlobalData::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 + +#if USE(CF) || OS(UNIX) + char* canUseJITString = getenv("JavaScriptCoreUseJIT"); + return !canUseJITString || atoi(canUseJITString); +#else + return true; +#endif } +#endif -JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType) - : globalDataType(globalDataType) +JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize) + : heap(this, heapSize) + , globalDataType(globalDataType) , clientData(0) - , arrayTable(fastNew(JSC::arrayTable)) + , topCallFrame(CallFrame::noCaller()) + , arrayConstructorTable(fastNew(JSC::arrayConstructorTable)) + , arrayPrototypeTable(fastNew(JSC::arrayPrototypeTable)) + , booleanPrototypeTable(fastNew(JSC::booleanPrototypeTable)) , dateTable(fastNew(JSC::dateTable)) + , dateConstructorTable(fastNew(JSC::dateConstructorTable)) + , errorPrototypeTable(fastNew(JSC::errorPrototypeTable)) + , globalObjectTable(fastNew(JSC::globalObjectTable)) , jsonTable(fastNew(JSC::jsonTable)) , mathTable(fastNew(JSC::mathTable)) - , numberTable(fastNew(JSC::numberTable)) + , numberConstructorTable(fastNew(JSC::numberConstructorTable)) + , numberPrototypeTable(fastNew(JSC::numberPrototypeTable)) + , objectConstructorTable(fastNew(JSC::objectConstructorTable)) + , objectPrototypeTable(fastNew(JSC::objectPrototypeTable)) , regExpTable(fastNew(JSC::regExpTable)) , regExpConstructorTable(fastNew(JSC::regExpConstructorTable)) + , regExpPrototypeTable(fastNew(JSC::regExpPrototypeTable)) , stringTable(fastNew(JSC::stringTable)) - , activationStructure(JSActivation::createStructure(jsNull())) - , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull())) - , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull())) - , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) - , stringStructure(JSString::createStructure(jsNull())) - , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull())) - , notAnObjectStructure(JSNotAnObject::createStructure(jsNull())) - , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull())) - , getterSetterStructure(GetterSetter::createStructure(jsNull())) - , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull())) - , dummyMarkableCellStructure(JSCell::createDummyStructure()) -#if USE(JSVALUE32) - , numberStructure(JSNumberCell::createStructure(jsNull())) -#endif + , stringConstructorTable(fastNew(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) - , heap(this) - , initializingLazyNumericCompareFunction(false) - , head(0) +#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 , dynamicGlobalObject(0) - , functionCodeBlockBeingReparsed(0) - , firstStringifierToMark(0) - , markStack(jsArrayVPtr) - , cachedUTCOffset(NaN) + , cachedUTCOffset(std::numeric_limits::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 PLATFORM(MAC) - startProfilerServerIfNeeded(); +#if CPU(X86) && ENABLE(JIT) + , m_timeoutCount(512) #endif -#if ENABLE(JIT) && ENABLE(INTERPRETER) -#if PLATFORM(CF) - CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); - CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); - if (canUseJIT) { - m_canUseJIT = kCFBooleanTrue == canUseJIT; - CFRelease(canUseJIT); - } else - m_canUseJIT = !getenv("JavaScriptCoreUseJIT"); - CFRelease(canUseJITKey); -#elif OS(UNIX) - m_canUseJIT = !getenv("JavaScriptCoreUseJIT"); -#else - m_canUseJIT = true; +#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT)) + , m_canUseAssembler(enableAssembler(executableAllocator)) #endif +#if ENABLE(GC_VALIDATION) + , m_initializingObjectClass(0) #endif + , m_inDefineOwnProperty(false) +{ + 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) -#if ENABLE(INTERPRETER) - if (m_canUseJIT) - m_canUseJIT = executableAllocator.isValid(); -#endif - jitStubs.set(new JITThunks(this)); + 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(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(arrayTable)); + fastDelete(const_cast(arrayConstructorTable)); + fastDelete(const_cast(arrayPrototypeTable)); + fastDelete(const_cast(booleanPrototypeTable)); fastDelete(const_cast(dateTable)); + fastDelete(const_cast(dateConstructorTable)); + fastDelete(const_cast(errorPrototypeTable)); + fastDelete(const_cast(globalObjectTable)); fastDelete(const_cast(jsonTable)); fastDelete(const_cast(mathTable)); - fastDelete(const_cast(numberTable)); + fastDelete(const_cast(numberConstructorTable)); + fastDelete(const_cast(numberPrototypeTable)); + fastDelete(const_cast(objectConstructorTable)); + fastDelete(const_cast(objectPrototypeTable)); fastDelete(const_cast(regExpTable)); fastDelete(const_cast(regExpConstructorTable)); + fastDelete(const_cast(regExpPrototypeTable)); fastDelete(const_cast(stringTable)); + fastDelete(const_cast(stringConstructorTable)); - delete parser; - delete lexer; - - deleteAllValues(opaqueJSClassData); + opaqueJSClassData.clear(); delete emptyList; @@ -220,24 +276,29 @@ JSGlobalData::~JSGlobalData() 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::createContextGroup(ThreadStackType type) +PassRefPtr JSGlobalData::createContextGroup(ThreadStackType type, HeapSize heapSize) { - return adoptRef(new JSGlobalData(APIContextGroup, type)); + return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize)); } -PassRefPtr JSGlobalData::create(ThreadStackType type) +PassRefPtr JSGlobalData::create(ThreadStackType type, HeapSize heapSize) { - return adoptRef(new JSGlobalData(Default, type)); + return adoptRef(new JSGlobalData(Default, type, heapSize)); } -PassRefPtr JSGlobalData::createLeaked(ThreadStackType type) +PassRefPtr JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize) { - Structure::startIgnoringLeaks(); - RefPtr data = create(type); - Structure::stopIgnoringLeaks(); - return data.release(); + return create(type, heapSize); } bool JSGlobalData::sharedInstanceExists() @@ -247,35 +308,71 @@ bool JSGlobalData::sharedInstanceExists() JSGlobalData& JSGlobalData::sharedInstance() { + GlobalJSLock globalLock; JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = new JSGlobalData(APIShared, ThreadStackTypeSmall); -#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& JSGlobalData::numericCompareFunction(ExecState* exec) +#if ENABLE(JIT) +static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) { - if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) { - initializingLazyNumericCompareFunction = true; - RefPtr function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); - lazyNumericCompareFunction = function->bytecode(exec, 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() { @@ -283,9 +380,10 @@ JSGlobalData::ClientData::~ClientData() void JSGlobalData::resetDateCache() { - cachedUTCOffset = NaN; + cachedUTCOffset = std::numeric_limits::quiet_NaN(); dstOffsetCache.reset(); cachedDateString = UString(); + cachedDateStringValue = std::numeric_limits::quiet_NaN(); dateInstanceCache.reset(); } @@ -302,23 +400,106 @@ void JSGlobalData::stopSampling() void JSGlobalData::dumpSampleData(ExecState* exec) { interpreter->dumpSampleData(exec); +#if ENABLE(ASSEMBLER) + ExecutableAllocator::dumpProfile(); +#endif +} + +struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { + HashSet currentlyExecutingFunctions; + void operator()(JSCell* cell) + { + if (!cell->inherits(&FunctionExecutable::s_info)) + return; + FunctionExecutable* executable = jsCast(cell); + if (currentlyExecutingFunctions.contains(executable)) + return; + executable->discardCode(); + } +}; + +void JSGlobalData::releaseExecutableMemory() +{ + if (dynamicGlobalObject) { + StackPreservingRecompiler recompiler; + HashSet roots; + heap.getConservativeRegisterRoots(roots); + HashSet::iterator end = roots.end(); + for (HashSet::iterator ptr = roots.begin(); ptr != end; ++ptr) { + ScriptExecutable* executable = 0; + JSCell* cell = *ptr; + if (cell->inherits(&ScriptExecutable::s_info)) + executable = static_cast(*ptr); + else if (cell->inherits(&JSFunction::s_info)) { + JSFunction* function = jsCast(*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(executable)); + + } + heap.objectSpace().forEachCell(recompiler); + } + m_regExpCache->invalidateCode(); + heap.collectAllGarbage(); } -void JSGlobalData::recompileAllJSFunctions() +#if ENABLE(ASSEMBLER) +void releaseExecutableMemory(JSGlobalData& globalData) +{ + globalData.releaseExecutableMemory(); +} +#endif + +#if ENABLE(DFG_JIT) +void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots) { - // 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); - - LiveObjectIterator it = heap.primaryHeapBegin(); - LiveObjectIterator heapEnd = heap.primaryHeapEnd(); - for ( ; it != heapEnd; ++it) { - if ((*it)->inherits(&JSFunction::info)) { - JSFunction* function = asFunction(*it); - if (!function->executable()->isHostFunction()) - function->jsExecutable()->recompile(); + 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(static_cast(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