]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSGlobalData.cpp
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / runtime / JSGlobalData.cpp
1 /*
2 * Copyright (C) 2008, 2011 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 "DebuggerActivation.h"
36 #include "FunctionConstructor.h"
37 #include "GetterSetter.h"
38 #include "Interpreter.h"
39 #include "JSActivation.h"
40 #include "JSAPIValueWrapper.h"
41 #include "JSArray.h"
42 #include "JSByteArray.h"
43 #include "JSClassRef.h"
44 #include "JSFunction.h"
45 #include "JSLock.h"
46 #include "JSNotAnObject.h"
47 #include "JSPropertyNameIterator.h"
48 #include "JSStaticScopeObject.h"
49 #include "JSZombie.h"
50 #include "Lexer.h"
51 #include "Lookup.h"
52 #include "Nodes.h"
53 #include "Parser.h"
54 #include "RegExpCache.h"
55 #include "RegExpObject.h"
56 #include "StrictEvalActivation.h"
57 #include <wtf/WTFThreadData.h>
58 #if ENABLE(REGEXP_TRACING)
59 #include "RegExp.h"
60 #endif
61
62
63 #if ENABLE(JSC_MULTIPLE_THREADS)
64 #include <wtf/Threading.h>
65 #endif
66
67 #if PLATFORM(MAC)
68 #include "ProfilerServer.h"
69 #include <CoreFoundation/CoreFoundation.h>
70 #endif
71
72 using namespace WTF;
73
74 namespace {
75
76 using namespace JSC;
77
78 class Recompiler {
79 public:
80 void operator()(JSCell*);
81 };
82
83 inline void Recompiler::operator()(JSCell* cell)
84 {
85 if (!cell->inherits(&JSFunction::s_info))
86 return;
87 JSFunction* function = asFunction(cell);
88 if (function->executable()->isHostFunction())
89 return;
90 function->jsExecutable()->discardCode();
91 }
92
93 } // namespace
94
95 namespace JSC {
96
97 extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable;
98 extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable;
99 extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable;
100 extern JSC_CONST_HASHTABLE HashTable jsonTable;
101 extern JSC_CONST_HASHTABLE HashTable dateTable;
102 extern JSC_CONST_HASHTABLE HashTable dateConstructorTable;
103 extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable;
104 extern JSC_CONST_HASHTABLE HashTable globalObjectTable;
105 extern JSC_CONST_HASHTABLE HashTable mathTable;
106 extern JSC_CONST_HASHTABLE HashTable numberConstructorTable;
107 extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable;
108 extern JSC_CONST_HASHTABLE HashTable objectConstructorTable;
109 extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable;
110 extern JSC_CONST_HASHTABLE HashTable regExpTable;
111 extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
112 extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable;
113 extern JSC_CONST_HASHTABLE HashTable stringTable;
114 extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
115
116 void* JSGlobalData::jsArrayVPtr;
117 void* JSGlobalData::jsByteArrayVPtr;
118 void* JSGlobalData::jsStringVPtr;
119 void* JSGlobalData::jsFunctionVPtr;
120
121 #if COMPILER(GCC)
122 // Work around for gcc trying to coalesce our reads of the various cell vptrs
123 #define CLOBBER_MEMORY() do { \
124 asm volatile ("" : : : "memory"); \
125 } while (false)
126 #else
127 #define CLOBBER_MEMORY() do { } while (false)
128 #endif
129
130 void JSGlobalData::storeVPtrs()
131 {
132 // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
133 // COMPILE_ASSERTS below check that this is true.
134 char storage[64];
135
136 COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
137 JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
138 CLOBBER_MEMORY();
139 JSGlobalData::jsArrayVPtr = jsArray->vptr();
140
141 COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
142 JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
143 CLOBBER_MEMORY();
144 JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
145
146 COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
147 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
148 CLOBBER_MEMORY();
149 JSGlobalData::jsStringVPtr = jsString->vptr();
150
151 COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
152 JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack);
153 CLOBBER_MEMORY();
154 JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
155 }
156
157 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
158 : globalDataType(globalDataType)
159 , clientData(0)
160 , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
161 , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
162 , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
163 , dateTable(fastNew<HashTable>(JSC::dateTable))
164 , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
165 , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
166 , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
167 , jsonTable(fastNew<HashTable>(JSC::jsonTable))
168 , mathTable(fastNew<HashTable>(JSC::mathTable))
169 , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
170 , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
171 , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
172 , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
173 , regExpTable(fastNew<HashTable>(JSC::regExpTable))
174 , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
175 , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
176 , stringTable(fastNew<HashTable>(JSC::stringTable))
177 , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
178 , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
179 , propertyNames(new CommonIdentifiers(this))
180 , emptyList(new MarkedArgumentBuffer)
181 #if ENABLE(ASSEMBLER)
182 , executableAllocator(*this)
183 , regexAllocator(*this)
184 #endif
185 , lexer(new Lexer(this))
186 , parser(new Parser)
187 , interpreter(0)
188 , heap(this)
189 , globalObjectCount(0)
190 , dynamicGlobalObject(0)
191 , cachedUTCOffset(NaN)
192 , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
193 , m_regExpCache(new RegExpCache(this))
194 #if ENABLE(REGEXP_TRACING)
195 , m_rtTraceList(new RTTraceList())
196 #endif
197 #ifndef NDEBUG
198 , exclusiveThread(0)
199 #endif
200 {
201 interpreter = new Interpreter(*this);
202 if (globalDataType == Default)
203 m_stack = wtfThreadData().stack();
204
205 // Need to be careful to keep everything consistent here
206 IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
207 JSLock lock(SilenceAssertionsOnly);
208 structureStructure.set(*this, Structure::createStructure(*this));
209 debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, jsNull()));
210 activationStructure.set(*this, JSActivation::createStructure(*this, jsNull()));
211 interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
212 terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
213 staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull()));
214 strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull()));
215 stringStructure.set(*this, JSString::createStructure(*this, jsNull()));
216 notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull()));
217 propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull()));
218 getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull()));
219 apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull()));
220 scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull()));
221 executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull()));
222 nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull()));
223 evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull()));
224 programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull()));
225 functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull()));
226 dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this));
227 regExpStructure.set(*this, RegExp::createStructure(*this, jsNull()));
228 structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull()));
229
230 #if ENABLE(JSC_ZOMBIES)
231 zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull()));
232 #endif
233
234 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
235
236 #if PLATFORM(MAC)
237 startProfilerServerIfNeeded();
238 #endif
239 #if ENABLE(JIT) && ENABLE(INTERPRETER)
240 #if USE(CF)
241 CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
242 CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
243 if (canUseJIT) {
244 m_canUseJIT = kCFBooleanTrue == canUseJIT;
245 CFRelease(canUseJIT);
246 } else {
247 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
248 m_canUseJIT = !canUseJITString || atoi(canUseJITString);
249 }
250 CFRelease(canUseJITKey);
251 #elif OS(UNIX)
252 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
253 m_canUseJIT = !canUseJITString || atoi(canUseJITString);
254 #else
255 m_canUseJIT = true;
256 #endif
257 #endif
258 #if ENABLE(JIT)
259 #if ENABLE(INTERPRETER)
260 if (m_canUseJIT)
261 m_canUseJIT = executableAllocator.isValid();
262 #endif
263 jitStubs = adoptPtr(new JITThunks(this));
264 #endif
265 }
266
267 void JSGlobalData::clearBuiltinStructures()
268 {
269 structureStructure.clear();
270 debuggerActivationStructure.clear();
271 activationStructure.clear();
272 interruptedExecutionErrorStructure.clear();
273 terminatedExecutionErrorStructure.clear();
274 staticScopeStructure.clear();
275 strictEvalActivationStructure.clear();
276 stringStructure.clear();
277 notAnObjectStructure.clear();
278 propertyNameIteratorStructure.clear();
279 getterSetterStructure.clear();
280 apiWrapperStructure.clear();
281 scopeChainNodeStructure.clear();
282 executableStructure.clear();
283 nativeExecutableStructure.clear();
284 evalExecutableStructure.clear();
285 programExecutableStructure.clear();
286 functionExecutableStructure.clear();
287 dummyMarkableCellStructure.clear();
288 regExpStructure.clear();
289 structureChainStructure.clear();
290
291 #if ENABLE(JSC_ZOMBIES)
292 zombieStructure.clear();
293 #endif
294 }
295
296 JSGlobalData::~JSGlobalData()
297 {
298 // By the time this is destroyed, heap.destroy() must already have been called.
299
300 delete interpreter;
301 #ifndef NDEBUG
302 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
303 interpreter = 0;
304 #endif
305
306 arrayPrototypeTable->deleteTable();
307 arrayConstructorTable->deleteTable();
308 booleanPrototypeTable->deleteTable();
309 dateTable->deleteTable();
310 dateConstructorTable->deleteTable();
311 errorPrototypeTable->deleteTable();
312 globalObjectTable->deleteTable();
313 jsonTable->deleteTable();
314 mathTable->deleteTable();
315 numberConstructorTable->deleteTable();
316 numberPrototypeTable->deleteTable();
317 objectConstructorTable->deleteTable();
318 objectPrototypeTable->deleteTable();
319 regExpTable->deleteTable();
320 regExpConstructorTable->deleteTable();
321 regExpPrototypeTable->deleteTable();
322 stringTable->deleteTable();
323 stringConstructorTable->deleteTable();
324
325 fastDelete(const_cast<HashTable*>(arrayConstructorTable));
326 fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
327 fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
328 fastDelete(const_cast<HashTable*>(dateTable));
329 fastDelete(const_cast<HashTable*>(dateConstructorTable));
330 fastDelete(const_cast<HashTable*>(errorPrototypeTable));
331 fastDelete(const_cast<HashTable*>(globalObjectTable));
332 fastDelete(const_cast<HashTable*>(jsonTable));
333 fastDelete(const_cast<HashTable*>(mathTable));
334 fastDelete(const_cast<HashTable*>(numberConstructorTable));
335 fastDelete(const_cast<HashTable*>(numberPrototypeTable));
336 fastDelete(const_cast<HashTable*>(objectConstructorTable));
337 fastDelete(const_cast<HashTable*>(objectPrototypeTable));
338 fastDelete(const_cast<HashTable*>(regExpTable));
339 fastDelete(const_cast<HashTable*>(regExpConstructorTable));
340 fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
341 fastDelete(const_cast<HashTable*>(stringTable));
342 fastDelete(const_cast<HashTable*>(stringConstructorTable));
343
344 delete parser;
345 delete lexer;
346
347 deleteAllValues(opaqueJSClassData);
348
349 delete emptyList;
350
351 delete propertyNames;
352 if (globalDataType != Default)
353 deleteIdentifierTable(identifierTable);
354
355 delete clientData;
356 delete m_regExpCache;
357 #if ENABLE(REGEXP_TRACING)
358 delete m_rtTraceList;
359 #endif
360 }
361
362 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
363 {
364 return adoptRef(new JSGlobalData(APIContextGroup, type));
365 }
366
367 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type)
368 {
369 return adoptRef(new JSGlobalData(Default, type));
370 }
371
372 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
373 {
374 return create(type);
375 }
376
377 bool JSGlobalData::sharedInstanceExists()
378 {
379 return sharedInstanceInternal();
380 }
381
382 JSGlobalData& JSGlobalData::sharedInstance()
383 {
384 JSGlobalData*& instance = sharedInstanceInternal();
385 if (!instance) {
386 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
387 #if ENABLE(JSC_MULTIPLE_THREADS)
388 instance->makeUsableFromMultipleThreads();
389 #endif
390 }
391 return *instance;
392 }
393
394 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
395 {
396 ASSERT(JSLock::currentThreadIsHoldingLock());
397 static JSGlobalData* sharedInstance;
398 return sharedInstance;
399 }
400
401 #if ENABLE(JIT)
402 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
403 {
404 return jitStubs->hostFunctionStub(this, function);
405 }
406 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
407 {
408 return jitStubs->hostFunctionStub(this, function, generator);
409 }
410 #else
411 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
412 {
413 return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
414 }
415 #endif
416
417 JSGlobalData::ClientData::~ClientData()
418 {
419 }
420
421 void JSGlobalData::resetDateCache()
422 {
423 cachedUTCOffset = NaN;
424 dstOffsetCache.reset();
425 cachedDateString = UString();
426 cachedDateStringValue = NaN;
427 dateInstanceCache.reset();
428 }
429
430 void JSGlobalData::startSampling()
431 {
432 interpreter->startSampling();
433 }
434
435 void JSGlobalData::stopSampling()
436 {
437 interpreter->stopSampling();
438 }
439
440 void JSGlobalData::dumpSampleData(ExecState* exec)
441 {
442 interpreter->dumpSampleData(exec);
443 }
444
445 void JSGlobalData::recompileAllJSFunctions()
446 {
447 // If JavaScript is running, it's not safe to recompile, since we'll end
448 // up throwing away code that is live on the stack.
449 ASSERT(!dynamicGlobalObject);
450
451 Recompiler recompiler;
452 heap.forEach(recompiler);
453 }
454
455 struct StackPreservingRecompiler {
456 HashSet<FunctionExecutable*> currentlyExecutingFunctions;
457 void operator()(JSCell* cell)
458 {
459 if (!cell->inherits(&FunctionExecutable::s_info))
460 return;
461 FunctionExecutable* executable = static_cast<FunctionExecutable*>(cell);
462 if (currentlyExecutingFunctions.contains(executable))
463 return;
464 executable->discardCode();
465 }
466 };
467
468 void JSGlobalData::releaseExecutableMemory()
469 {
470 if (dynamicGlobalObject) {
471 StackPreservingRecompiler recompiler;
472 HashSet<JSCell*> roots;
473 heap.getConservativeRegisterRoots(roots);
474 HashSet<JSCell*>::iterator end = roots.end();
475 for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
476 ScriptExecutable* executable = 0;
477 JSCell* cell = *ptr;
478 if (cell->inherits(&ScriptExecutable::s_info))
479 executable = static_cast<ScriptExecutable*>(*ptr);
480 else if (cell->inherits(&JSFunction::s_info)) {
481 JSFunction* function = asFunction(*ptr);
482 if (function->isHostFunction())
483 continue;
484 executable = function->jsExecutable();
485 } else
486 continue;
487 ASSERT(executable->inherits(&ScriptExecutable::s_info));
488 executable->unlinkCalls();
489 if (executable->inherits(&FunctionExecutable::s_info))
490 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
491
492 }
493 heap.forEach(recompiler);
494 } else
495 recompileAllJSFunctions();
496
497 m_regExpCache->invalidateCode();
498 heap.collectAllGarbage();
499 }
500
501 #if ENABLE(ASSEMBLER)
502 void releaseExecutableMemory(JSGlobalData& globalData)
503 {
504 globalData.releaseExecutableMemory();
505 }
506 #endif
507
508 #if ENABLE(REGEXP_TRACING)
509 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
510 {
511 m_rtTraceList->add(regExp);
512 }
513
514 void JSGlobalData::dumpRegExpTrace()
515 {
516 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
517 RTTraceList::iterator iter = ++m_rtTraceList->begin();
518
519 if (iter != m_rtTraceList->end()) {
520 printf("\nRegExp Tracing\n");
521 printf(" match() matches\n");
522 printf("Regular Expression JIT Address calls found\n");
523 printf("----------------------------------------+----------------+----------+----------\n");
524
525 unsigned reCount = 0;
526
527 for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
528 (*iter)->printTraceData();
529
530 printf("%d Regular Expressions\n", reCount);
531 }
532
533 m_rtTraceList->clear();
534 }
535 #else
536 void JSGlobalData::dumpRegExpTrace()
537 {
538 }
539 #endif
540
541 } // namespace JSC