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 70 using namespace WTF; 71 72 namespace { 73 74 using namespace JSC; 75 76 class Recompiler { 77 public: 78 void operator()(JSCell*); 79 }; 80 81 inline 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 93 namespace JSC { 94 95 extern JSC_CONST_HASHTABLE HashTable arrayTable; 96 extern JSC_CONST_HASHTABLE HashTable jsonTable; 97 extern JSC_CONST_HASHTABLE HashTable dateTable; 98 extern JSC_CONST_HASHTABLE HashTable mathTable; 99 extern JSC_CONST_HASHTABLE HashTable numberTable; 100 extern JSC_CONST_HASHTABLE HashTable objectConstructorTable; 101 extern JSC_CONST_HASHTABLE HashTable regExpTable; 102 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable; 103 extern JSC_CONST_HASHTABLE HashTable stringTable; 104 105 void* JSGlobalData::jsArrayVPtr; 106 void* JSGlobalData::jsByteArrayVPtr; 107 void* JSGlobalData::jsStringVPtr; 108 void* 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 119 void 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 146 JSGlobalData::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 241 void 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 268 JSGlobalData::~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 316 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type) 317 { 318 return adoptRef(new JSGlobalData(APIContextGroup, type)); 319 } 320 321 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type) 322 { 323 return adoptRef(new JSGlobalData(Default, type)); 324 } 325 326 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type) 327 { 328 return create(type); 329 } 330 331 bool JSGlobalData::sharedInstanceExists() 332 { 333 return sharedInstanceInternal(); 334 } 335 336 JSGlobalData& 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 348 JSGlobalData*& JSGlobalData::sharedInstanceInternal() 349 { 350 ASSERT(JSLock::currentThreadIsHoldingLock()); 351 static JSGlobalData* sharedInstance; 352 return sharedInstance; 353 } 354 355 #if ENABLE(JIT) 356 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) 357 { 358 return jitStubs->hostFunctionStub(this, function); 359 } 360 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator) 361 { 362 return jitStubs->hostFunctionStub(this, function, generator); 363 } 364 #else 365 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) 366 { 367 return NativeExecutable::create(*this, function, callHostFunctionAsConstructor); 368 } 369 #endif 370 371 JSGlobalData::ClientData::~ClientData() 372 { 373 } 374 375 void JSGlobalData::resetDateCache() 376 { 377 cachedUTCOffset = NaN; 378 dstOffsetCache.reset(); 379 cachedDateString = UString(); 380 cachedDateStringValue = NaN; 381 dateInstanceCache.reset(); 382 } 383 384 void JSGlobalData::startSampling() 385 { 386 interpreter->startSampling(); 387 } 388 389 void JSGlobalData::stopSampling() 390 { 391 interpreter->stopSampling(); 392 } 393 394 void JSGlobalData::dumpSampleData(ExecState* exec) 395 { 396 interpreter->dumpSampleData(exec); 397 } 398 399 void 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) 410 void JSGlobalData::addRegExpToTrace(PassRefPtr<RegExp> regExp) 411 { 412 m_rtTraceList->add(regExp); 413 } 414 415 void 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 437 void JSGlobalData::dumpRegExpTrace() 438 { 439 } 440 #endif 441 442 } // namespace JSC 443