/*
- * 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 "CollectorHeapIterator.h"
+#include "Heap.h"
#include "CommonIdentifiers.h"
+#include "DebuggerActivation.h"
#include "FunctionConstructor.h"
#include "GetterSetter.h"
#include "Interpreter.h"
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
#include "JSStaticScopeObject.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>
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 JSC_CONST_HASHTABLE HashTable arrayTable;
+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 numberTable;
+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()
{
- CollectorCell cell;
- void* storage = &cell;
+ // 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(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell);
- JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
+ 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();
- jsArray->~JSCell();
- COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell);
+ 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();
- jsByteArray->~JSCell();
- COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell);
+ 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();
- jsString->~JSCell();
- COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell);
- JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
+ 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();
- jsFunction->~JSCell();
}
JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
: globalDataType(globalDataType)
, clientData(0)
- , arrayTable(fastNew<HashTable>(JSC::arrayTable))
+ , 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()))
- , 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<HashTable>(JSC::stringConstructorTable))
, identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
, emptyList(new MarkedArgumentBuffer)
+#if ENABLE(ASSEMBLER)
+ , executableAllocator(*this)
+ , regexAllocator(*this)
+#endif
, lexer(new Lexer(this))
, parser(new Parser)
- , interpreter(new Interpreter)
+ , interpreter(0)
, heap(this)
- , initializingLazyNumericCompareFunction(false)
- , head(0)
+ , globalObjectCount(0)
, dynamicGlobalObject(0)
- , functionCodeBlockBeingReparsed(0)
- , firstStringifierToMark(0)
- , markStack(jsArrayVPtr)
, 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
#if ENABLE(JIT) && ENABLE(INTERPRETER)
-#if PLATFORM(CF)
+#if USE(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");
+ } else {
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+ }
CFRelease(canUseJITKey);
#elif OS(UNIX)
- m_canUseJIT = !getenv("JavaScriptCoreUseJIT");
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
#else
m_canUseJIT = true;
#endif
if (m_canUseJIT)
m_canUseJIT = executableAllocator.isValid();
#endif
- jitStubs.set(new JITThunks(this));
+ 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
}
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();
+ 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;
delete clientData;
delete m_regExpCache;
+#if ENABLE(REGEXP_TRACING)
+ delete m_rtTraceList;
+#endif
}
PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
{
- Structure::startIgnoringLeaks();
- RefPtr<JSGlobalData> data = create(type);
- Structure::stopIgnoringLeaks();
- return data.release();
+ return create(type);
}
bool JSGlobalData::sharedInstanceExists()
{
JSGlobalData*& instance = sharedInstanceInternal();
if (!instance) {
- instance = new JSGlobalData(APIShared, ThreadStackTypeSmall);
+ instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
#if ENABLE(JSC_MULTIPLE_THREADS)
instance->makeUsableFromMultipleThreads();
#endif
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)
{
- if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) {
- initializingLazyNumericCompareFunction = true;
- RefPtr<FunctionExecutable> 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;
- }
-
- return lazyNumericCompareFunction;
+ 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()
{
cachedUTCOffset = NaN;
dstOffsetCache.reset();
cachedDateString = UString();
+ cachedDateStringValue = NaN;
dateInstanceCache.reset();
}
// 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();
+ }
+};
- 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();
+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();
+}
+
+#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