Home | History | Annotate | Download | only in runtime
      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