• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
operator ()(JSCell * cell)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 
storeVPtrs()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 
JSGlobalData(GlobalDataType globalDataType,ThreadStackType threadStackType)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 
clearBuiltinStructures()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 
~JSGlobalData()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 
createContextGroup(ThreadStackType type)316 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
317 {
318     return adoptRef(new JSGlobalData(APIContextGroup, type));
319 }
320 
create(ThreadStackType type)321 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type)
322 {
323     return adoptRef(new JSGlobalData(Default, type));
324 }
325 
createLeaked(ThreadStackType type)326 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
327 {
328     return create(type);
329 }
330 
sharedInstanceExists()331 bool JSGlobalData::sharedInstanceExists()
332 {
333     return sharedInstanceInternal();
334 }
335 
sharedInstance()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 
sharedInstanceInternal()348 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
349 {
350     ASSERT(JSLock::currentThreadIsHoldingLock());
351     static JSGlobalData* sharedInstance;
352     return sharedInstance;
353 }
354 
355 #if ENABLE(JIT)
getHostFunction(NativeFunction function)356 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
357 {
358     return jitStubs->hostFunctionStub(this, function);
359 }
getHostFunction(NativeFunction function,ThunkGenerator generator)360 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
361 {
362     return jitStubs->hostFunctionStub(this, function, generator);
363 }
364 #else
getHostFunction(NativeFunction function)365 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
366 {
367     return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
368 }
369 #endif
370 
~ClientData()371 JSGlobalData::ClientData::~ClientData()
372 {
373 }
374 
resetDateCache()375 void JSGlobalData::resetDateCache()
376 {
377     cachedUTCOffset = NaN;
378     dstOffsetCache.reset();
379     cachedDateString = UString();
380     cachedDateStringValue = NaN;
381     dateInstanceCache.reset();
382 }
383 
startSampling()384 void JSGlobalData::startSampling()
385 {
386     interpreter->startSampling();
387 }
388 
stopSampling()389 void JSGlobalData::stopSampling()
390 {
391     interpreter->stopSampling();
392 }
393 
dumpSampleData(ExecState * exec)394 void JSGlobalData::dumpSampleData(ExecState* exec)
395 {
396     interpreter->dumpSampleData(exec);
397 }
398 
recompileAllJSFunctions()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)
addRegExpToTrace(PassRefPtr<RegExp> regExp)410 void JSGlobalData::addRegExpToTrace(PassRefPtr<RegExp> regExp)
411 {
412     m_rtTraceList->add(regExp);
413 }
414 
dumpRegExpTrace()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
dumpRegExpTrace()437 void JSGlobalData::dumpRegExpTrace()
438 {
439 }
440 #endif
441 
442 } // namespace JSC
443