1/* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "JSGlobalData.h" 31 32#include "ArgList.h" 33#include "Heap.h" 34#include "CommonIdentifiers.h" 35#include "FunctionConstructor.h" 36#include "GetterSetter.h" 37#include "Interpreter.h" 38#include "JSActivation.h" 39#include "JSAPIValueWrapper.h" 40#include "JSArray.h" 41#include "JSByteArray.h" 42#include "JSClassRef.h" 43#include "JSFunction.h" 44#include "JSLock.h" 45#include "JSNotAnObject.h" 46#include "JSPropertyNameIterator.h" 47#include "JSStaticScopeObject.h" 48#include "JSZombie.h" 49#include "Lexer.h" 50#include "Lookup.h" 51#include "Nodes.h" 52#include "Parser.h" 53#include "RegExpCache.h" 54#include "StrictEvalActivation.h" 55#include <wtf/WTFThreadData.h> 56#if ENABLE(REGEXP_TRACING) 57#include "RegExp.h" 58#endif 59 60 61#if ENABLE(JSC_MULTIPLE_THREADS) 62#include <wtf/Threading.h> 63#endif 64 65#if PLATFORM(MAC) 66#include "ProfilerServer.h" 67#include <CoreFoundation/CoreFoundation.h> 68#endif 69 70using namespace WTF; 71 72namespace { 73 74using namespace JSC; 75 76class Recompiler { 77public: 78 void operator()(JSCell*); 79}; 80 81inline void Recompiler::operator()(JSCell* cell) 82{ 83 if (!cell->inherits(&JSFunction::s_info)) 84 return; 85 JSFunction* function = asFunction(cell); 86 if (function->executable()->isHostFunction()) 87 return; 88 function->jsExecutable()->discardCode(); 89} 90 91} // namespace 92 93namespace JSC { 94 95extern JSC_CONST_HASHTABLE HashTable arrayTable; 96extern JSC_CONST_HASHTABLE HashTable jsonTable; 97extern JSC_CONST_HASHTABLE HashTable dateTable; 98extern JSC_CONST_HASHTABLE HashTable mathTable; 99extern JSC_CONST_HASHTABLE HashTable numberTable; 100extern JSC_CONST_HASHTABLE HashTable objectConstructorTable; 101extern JSC_CONST_HASHTABLE HashTable regExpTable; 102extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable; 103extern JSC_CONST_HASHTABLE HashTable stringTable; 104 105void* JSGlobalData::jsArrayVPtr; 106void* JSGlobalData::jsByteArrayVPtr; 107void* JSGlobalData::jsStringVPtr; 108void* JSGlobalData::jsFunctionVPtr; 109 110#if COMPILER(GCC) 111// Work around for gcc trying to coalesce our reads of the various cell vptrs 112#define CLOBBER_MEMORY() do { \ 113 asm volatile ("" : : : "memory"); \ 114} while (false) 115#else 116#define CLOBBER_MEMORY() do { } while (false) 117#endif 118 119void JSGlobalData::storeVPtrs() 120{ 121 // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction. 122 // COMPILE_ASSERTS below check that this is true. 123 char storage[64]; 124 125 COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage); 126 JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack); 127 CLOBBER_MEMORY(); 128 JSGlobalData::jsArrayVPtr = jsArray->vptr(); 129 130 COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage); 131 JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); 132 CLOBBER_MEMORY(); 133 JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); 134 135 COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage); 136 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); 137 CLOBBER_MEMORY(); 138 JSGlobalData::jsStringVPtr = jsString->vptr(); 139 140 COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage); 141 JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack); 142 CLOBBER_MEMORY(); 143 JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); 144} 145 146JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType) 147 : globalDataType(globalDataType) 148 , clientData(0) 149 , arrayTable(fastNew<HashTable>(JSC::arrayTable)) 150 , dateTable(fastNew<HashTable>(JSC::dateTable)) 151 , jsonTable(fastNew<HashTable>(JSC::jsonTable)) 152 , mathTable(fastNew<HashTable>(JSC::mathTable)) 153 , numberTable(fastNew<HashTable>(JSC::numberTable)) 154 , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable)) 155 , regExpTable(fastNew<HashTable>(JSC::regExpTable)) 156 , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable)) 157 , stringTable(fastNew<HashTable>(JSC::stringTable)) 158 , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) 159 , propertyNames(new CommonIdentifiers(this)) 160 , emptyList(new MarkedArgumentBuffer) 161 , lexer(new Lexer(this)) 162 , parser(new Parser) 163 , interpreter(0) 164 , heap(this) 165 , globalObjectCount(0) 166 , dynamicGlobalObject(0) 167 , cachedUTCOffset(NaN) 168 , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) 169 , m_regExpCache(new RegExpCache(this)) 170#if ENABLE(REGEXP_TRACING) 171 , m_rtTraceList(new RTTraceList()) 172#endif 173#ifndef NDEBUG 174 , exclusiveThread(0) 175#endif 176{ 177 interpreter = new Interpreter(*this); 178 if (globalDataType == Default) 179 m_stack = wtfThreadData().stack(); 180 181 // Need to be careful to keep everything consistent here 182 IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); 183 JSLock lock(SilenceAssertionsOnly); 184 structureStructure.set(*this, Structure::createStructure(*this)); 185 activationStructure.set(*this, JSActivation::createStructure(*this, jsNull())); 186 interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull())); 187 terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull())); 188 staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull())); 189 strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull())); 190 stringStructure.set(*this, JSString::createStructure(*this, jsNull())); 191 notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull())); 192 propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull())); 193 getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull())); 194 apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull())); 195 scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull())); 196 executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull())); 197 nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull())); 198 evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull())); 199 programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull())); 200 functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull())); 201 dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this)); 202 structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull())); 203 204#if ENABLE(JSC_ZOMBIES) 205 zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull())); 206#endif 207 208 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); 209 210#if PLATFORM(MAC) 211 startProfilerServerIfNeeded(); 212#endif 213#if ENABLE(JIT) && ENABLE(INTERPRETER) 214#if USE(CF) 215 CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); 216 CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); 217 if (canUseJIT) { 218 m_canUseJIT = kCFBooleanTrue == canUseJIT; 219 CFRelease(canUseJIT); 220 } else { 221 char* canUseJITString = getenv("JavaScriptCoreUseJIT"); 222 m_canUseJIT = !canUseJITString || atoi(canUseJITString); 223 } 224 CFRelease(canUseJITKey); 225#elif OS(UNIX) 226 char* canUseJITString = getenv("JavaScriptCoreUseJIT"); 227 m_canUseJIT = !canUseJITString || atoi(canUseJITString); 228#else 229 m_canUseJIT = true; 230#endif 231#endif 232#if ENABLE(JIT) 233#if ENABLE(INTERPRETER) 234 if (m_canUseJIT) 235 m_canUseJIT = executableAllocator.isValid(); 236#endif 237 jitStubs = new JITThunks(this); 238#endif 239} 240 241void JSGlobalData::clearBuiltinStructures() 242{ 243 structureStructure.clear(); 244 activationStructure.clear(); 245 interruptedExecutionErrorStructure.clear(); 246 terminatedExecutionErrorStructure.clear(); 247 staticScopeStructure.clear(); 248 strictEvalActivationStructure.clear(); 249 stringStructure.clear(); 250 notAnObjectStructure.clear(); 251 propertyNameIteratorStructure.clear(); 252 getterSetterStructure.clear(); 253 apiWrapperStructure.clear(); 254 scopeChainNodeStructure.clear(); 255 executableStructure.clear(); 256 nativeExecutableStructure.clear(); 257 evalExecutableStructure.clear(); 258 programExecutableStructure.clear(); 259 functionExecutableStructure.clear(); 260 dummyMarkableCellStructure.clear(); 261 structureChainStructure.clear(); 262 263#if ENABLE(JSC_ZOMBIES) 264 zombieStructure.clear(); 265#endif 266} 267 268JSGlobalData::~JSGlobalData() 269{ 270 // By the time this is destroyed, heap.destroy() must already have been called. 271 272 delete interpreter; 273#ifndef NDEBUG 274 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance. 275 interpreter = 0; 276#endif 277 278 arrayTable->deleteTable(); 279 dateTable->deleteTable(); 280 jsonTable->deleteTable(); 281 mathTable->deleteTable(); 282 numberTable->deleteTable(); 283 objectConstructorTable->deleteTable(); 284 regExpTable->deleteTable(); 285 regExpConstructorTable->deleteTable(); 286 stringTable->deleteTable(); 287 288 fastDelete(const_cast<HashTable*>(arrayTable)); 289 fastDelete(const_cast<HashTable*>(dateTable)); 290 fastDelete(const_cast<HashTable*>(jsonTable)); 291 fastDelete(const_cast<HashTable*>(mathTable)); 292 fastDelete(const_cast<HashTable*>(numberTable)); 293 fastDelete(const_cast<HashTable*>(objectConstructorTable)); 294 fastDelete(const_cast<HashTable*>(regExpTable)); 295 fastDelete(const_cast<HashTable*>(regExpConstructorTable)); 296 fastDelete(const_cast<HashTable*>(stringTable)); 297 298 delete parser; 299 delete lexer; 300 301 deleteAllValues(opaqueJSClassData); 302 303 delete emptyList; 304 305 delete propertyNames; 306 if (globalDataType != Default) 307 deleteIdentifierTable(identifierTable); 308 309 delete clientData; 310 delete m_regExpCache; 311#if ENABLE(REGEXP_TRACING) 312 delete m_rtTraceList; 313#endif 314} 315 316PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type) 317{ 318 return adoptRef(new JSGlobalData(APIContextGroup, type)); 319} 320 321PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type) 322{ 323 return adoptRef(new JSGlobalData(Default, type)); 324} 325 326PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type) 327{ 328 return create(type); 329} 330 331bool JSGlobalData::sharedInstanceExists() 332{ 333 return sharedInstanceInternal(); 334} 335 336JSGlobalData& JSGlobalData::sharedInstance() 337{ 338 JSGlobalData*& instance = sharedInstanceInternal(); 339 if (!instance) { 340 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef(); 341#if ENABLE(JSC_MULTIPLE_THREADS) 342 instance->makeUsableFromMultipleThreads(); 343#endif 344 } 345 return *instance; 346} 347 348JSGlobalData*& JSGlobalData::sharedInstanceInternal() 349{ 350 ASSERT(JSLock::currentThreadIsHoldingLock()); 351 static JSGlobalData* sharedInstance; 352 return sharedInstance; 353} 354 355#if ENABLE(JIT) 356NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) 357{ 358 return jitStubs->hostFunctionStub(this, function); 359} 360NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator) 361{ 362 return jitStubs->hostFunctionStub(this, function, generator); 363} 364#else 365NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) 366{ 367 return NativeExecutable::create(*this, function, callHostFunctionAsConstructor); 368} 369#endif 370 371JSGlobalData::ClientData::~ClientData() 372{ 373} 374 375void JSGlobalData::resetDateCache() 376{ 377 cachedUTCOffset = NaN; 378 dstOffsetCache.reset(); 379 cachedDateString = UString(); 380 cachedDateStringValue = NaN; 381 dateInstanceCache.reset(); 382} 383 384void JSGlobalData::startSampling() 385{ 386 interpreter->startSampling(); 387} 388 389void JSGlobalData::stopSampling() 390{ 391 interpreter->stopSampling(); 392} 393 394void JSGlobalData::dumpSampleData(ExecState* exec) 395{ 396 interpreter->dumpSampleData(exec); 397} 398 399void JSGlobalData::recompileAllJSFunctions() 400{ 401 // If JavaScript is running, it's not safe to recompile, since we'll end 402 // up throwing away code that is live on the stack. 403 ASSERT(!dynamicGlobalObject); 404 405 Recompiler recompiler; 406 heap.forEach(recompiler); 407} 408 409#if ENABLE(REGEXP_TRACING) 410void JSGlobalData::addRegExpToTrace(PassRefPtr<RegExp> regExp) 411{ 412 m_rtTraceList->add(regExp); 413} 414 415void JSGlobalData::dumpRegExpTrace() 416{ 417 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used. 418 RTTraceList::iterator iter = ++m_rtTraceList->begin(); 419 420 if (iter != m_rtTraceList->end()) { 421 printf("\nRegExp Tracing\n"); 422 printf(" match() matches\n"); 423 printf("Regular Expression JIT Address calls found\n"); 424 printf("----------------------------------------+----------------+----------+----------\n"); 425 426 unsigned reCount = 0; 427 428 for (; iter != m_rtTraceList->end(); ++iter, ++reCount) 429 (*iter)->printTraceData(); 430 431 printf("%d Regular Expressions\n", reCount); 432 } 433 434 m_rtTraceList->clear(); 435} 436#else 437void JSGlobalData::dumpRegExpTrace() 438{ 439} 440#endif 441 442} // namespace JSC 443