diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/runtime/JSGlobalData.cpp | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSGlobalData.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSGlobalData.cpp | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp new file mode 100644 index 000000000..dab3f24ba --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -0,0 +1,528 @@ +/* + * 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 "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 "Lexer.h" +#include "Lookup.h" +#include "Nodes.h" +#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(REGEXP_TRACING) +#include "RegExp.h" +#endif + +#if PLATFORM(MAC) +#include <CoreFoundation/CoreFoundation.h> +#endif + +using namespace WTF; + +namespace { + +using namespace JSC; + +class Recompiler : public MarkedBlock::VoidFunctor { +public: + void operator()(JSCell*); +}; + +inline void Recompiler::operator()(JSCell* cell) +{ + if (!cell->inherits(&JSFunction::s_info)) + return; + JSFunction* function = asFunction(cell); + if (!function->executable() || function->executable()->isHostFunction()) + return; + function->jsExecutable()->discardCode(); +} + +} // namespace + +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; +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; + +JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize) + : 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)) + , 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) +#if ENABLE(ASSEMBLER) + , executableAllocator(*this) +#endif + , parserArena(adoptPtr(new ParserArena)) + , keywords(adoptPtr(new Keywords(this))) + , interpreter(0) + , heap(this, heapSize) +#if ENABLE(DFG_JIT) + , sizeOfLastScratchBuffer(0) +#endif + , dynamicGlobalObject(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(GC_VALIDATION) + , m_isInitializingObject(false) +#endif +{ + interpreter = new Interpreter; + 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, 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) && 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 + + interpreter->initialize(this->canUseJIT()); + + heap.notifyIsSafeToCollect(); +} + +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(); + regExpStructure.clear(); + structureChainStructure.clear(); +} + +JSGlobalData::~JSGlobalData() +{ + // By the time this is destroyed, heap.destroy() must already have been called. + + delete interpreter; +#ifndef NDEBUG + // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance. + interpreter = 0; +#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(); + 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*>(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(ThreadStackType type, HeapSize heapSize) +{ + return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize)); +} + +PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapSize heapSize) +{ + return adoptRef(new JSGlobalData(Default, type, heapSize)); +} + +PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize) +{ + return create(type, heapSize); +} + +bool JSGlobalData::sharedInstanceExists() +{ + return sharedInstanceInternal(); +} + +JSGlobalData& JSGlobalData::sharedInstance() +{ + JSGlobalData*& instance = sharedInstanceInternal(); + if (!instance) { + instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef(); + instance->makeUsableFromMultipleThreads(); + } + return *instance; +} + +JSGlobalData*& JSGlobalData::sharedInstanceInternal() +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + 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) +{ +#if ENABLE(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 +} + +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); + + heap.objectSpace().forEachCell<Recompiler>(); +} + +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 = 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.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler); + } + m_regExpCache->invalidateCode(); + heap.collectAllGarbage(); +} + +void releaseExecutableMemory(JSGlobalData& globalData) +{ + globalData.releaseExecutableMemory(); +} + +#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 |