]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSGlobalData.cpp
JavaScriptCore-1097.3.3.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 "GCActivityCallback.h"
38 #include "GetterSetter.h"
39 #include "HostCallReturnValue.h"
40 #include "Interpreter.h"
41 #include "JSActivation.h"
42 #include "JSAPIValueWrapper.h"
43 #include "JSArray.h"
44 #include "JSClassRef.h"
45 #include "JSFunction.h"
46 #include "JSLock.h"
47 #include "JSNotAnObject.h"
48 #include "JSPropertyNameIterator.h"
49 #include "JSStaticScopeObject.h"
50 #include "Lexer.h"
51 #include "Lookup.h"
52 #include "Nodes.h"
53 #include "ParserArena.h"
54 #include "RegExpCache.h"
55 #include "RegExpObject.h"
56 #include "StrictEvalActivation.h"
57 #include "StrongInlines.h"
58 #include <wtf/Threading.h>
59 #include <wtf/WTFThreadData.h>
60
61 #if ENABLE(DFG_JIT)
62 #include "ConservativeRoots.h"
63 #endif
64
65 #if ENABLE(REGEXP_TRACING)
66 #include "RegExp.h"
67 #endif
68
69 #if USE(CF)
70 #include <CoreFoundation/CoreFoundation.h>
71 #endif
72
73 using namespace WTF;
74
75 namespace JSC {
76
77 extern const HashTable arrayConstructorTable;
78 extern const HashTable arrayPrototypeTable;
79 extern const HashTable booleanPrototypeTable;
80 extern const HashTable jsonTable;
81 extern const HashTable dateTable;
82 extern const HashTable dateConstructorTable;
83 extern const HashTable errorPrototypeTable;
84 extern const HashTable globalObjectTable;
85 extern const HashTable mathTable;
86 extern const HashTable numberConstructorTable;
87 extern const HashTable numberPrototypeTable;
88 JS_EXPORTDATA extern const HashTable objectConstructorTable;
89 extern const HashTable objectPrototypeTable;
90 extern const HashTable regExpTable;
91 extern const HashTable regExpConstructorTable;
92 extern const HashTable regExpPrototypeTable;
93 extern const HashTable stringTable;
94 extern const HashTable stringConstructorTable;
95
96 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
97 static bool enableAssembler(ExecutableAllocator& executableAllocator)
98 {
99 if (!executableAllocator.isValid() || !Options::useJIT)
100 return false;
101 #if USE(CF)
102 CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
103 CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
104 if (canUseJIT) {
105 return kCFBooleanTrue == canUseJIT;
106 CFRelease(canUseJIT);
107 }
108 CFRelease(canUseJITKey);
109 #endif
110
111 #if USE(CF) || OS(UNIX)
112 char* canUseJITString = getenv("JavaScriptCoreUseJIT");
113 return !canUseJITString || atoi(canUseJITString);
114 #else
115 return true;
116 #endif
117 }
118 #endif
119
120 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize)
121 : heap(this, heapSize)
122 , globalDataType(globalDataType)
123 , clientData(0)
124 , topCallFrame(CallFrame::noCaller())
125 , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
126 , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
127 , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
128 , dateTable(fastNew<HashTable>(JSC::dateTable))
129 , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
130 , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
131 , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
132 , jsonTable(fastNew<HashTable>(JSC::jsonTable))
133 , mathTable(fastNew<HashTable>(JSC::mathTable))
134 , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
135 , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
136 , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
137 , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
138 , regExpTable(fastNew<HashTable>(JSC::regExpTable))
139 , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
140 , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
141 , stringTable(fastNew<HashTable>(JSC::stringTable))
142 , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
143 , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
144 , propertyNames(new CommonIdentifiers(this))
145 , emptyList(new MarkedArgumentBuffer)
146 #if ENABLE(ASSEMBLER)
147 , executableAllocator(*this)
148 #endif
149 , parserArena(adoptPtr(new ParserArena))
150 , keywords(adoptPtr(new Keywords(this)))
151 , interpreter(0)
152 , jsArrayClassInfo(&JSArray::s_info)
153 , jsFinalObjectClassInfo(&JSFinalObject::s_info)
154 #if ENABLE(DFG_JIT)
155 , sizeOfLastScratchBuffer(0)
156 #endif
157 , dynamicGlobalObject(0)
158 , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
159 , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
160 , m_regExpCache(new RegExpCache(this))
161 #if ENABLE(REGEXP_TRACING)
162 , m_rtTraceList(new RTTraceList())
163 #endif
164 #ifndef NDEBUG
165 , exclusiveThread(0)
166 #endif
167 #if CPU(X86) && ENABLE(JIT)
168 , m_timeoutCount(512)
169 #endif
170 #if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
171 , m_canUseAssembler(enableAssembler(executableAllocator))
172 #endif
173 #if ENABLE(GC_VALIDATION)
174 , m_initializingObjectClass(0)
175 #endif
176 , m_inDefineOwnProperty(false)
177 {
178 interpreter = new Interpreter;
179
180 // Need to be careful to keep everything consistent here
181 JSLockHolder lock(this);
182 IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
183 structureStructure.set(*this, Structure::createStructure(*this));
184 debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
185 activationStructure.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
186 interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
187 terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
188 staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
189 strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, 0, jsNull()));
190 stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
191 notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
192 propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
193 getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
194 apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
195 scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, 0, jsNull()));
196 executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
197 nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
198 evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
199 programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
200 functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
201 regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
202 structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
203
204 wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
205
206 #if ENABLE(JIT)
207 jitStubs = adoptPtr(new JITThunks(this));
208 #endif
209
210 interpreter->initialize(&llintData, this->canUseJIT());
211
212 initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
213
214 heap.notifyIsSafeToCollect();
215
216 llintData.performAssertions(*this);
217 }
218
219 JSGlobalData::~JSGlobalData()
220 {
221 ASSERT(!m_apiLock.currentThreadIsHoldingLock());
222 if (heap.activityCallback())
223 heap.activityCallback()->didStartVMShutdown();
224 heap.lastChanceToFinalize();
225
226 delete interpreter;
227 #ifndef NDEBUG
228 interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
229 #endif
230
231 arrayPrototypeTable->deleteTable();
232 arrayConstructorTable->deleteTable();
233 booleanPrototypeTable->deleteTable();
234 dateTable->deleteTable();
235 dateConstructorTable->deleteTable();
236 errorPrototypeTable->deleteTable();
237 globalObjectTable->deleteTable();
238 jsonTable->deleteTable();
239 mathTable->deleteTable();
240 numberConstructorTable->deleteTable();
241 numberPrototypeTable->deleteTable();
242 objectConstructorTable->deleteTable();
243 objectPrototypeTable->deleteTable();
244 regExpTable->deleteTable();
245 regExpConstructorTable->deleteTable();
246 regExpPrototypeTable->deleteTable();
247 stringTable->deleteTable();
248 stringConstructorTable->deleteTable();
249
250 fastDelete(const_cast<HashTable*>(arrayConstructorTable));
251 fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
252 fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
253 fastDelete(const_cast<HashTable*>(dateTable));
254 fastDelete(const_cast<HashTable*>(dateConstructorTable));
255 fastDelete(const_cast<HashTable*>(errorPrototypeTable));
256 fastDelete(const_cast<HashTable*>(globalObjectTable));
257 fastDelete(const_cast<HashTable*>(jsonTable));
258 fastDelete(const_cast<HashTable*>(mathTable));
259 fastDelete(const_cast<HashTable*>(numberConstructorTable));
260 fastDelete(const_cast<HashTable*>(numberPrototypeTable));
261 fastDelete(const_cast<HashTable*>(objectConstructorTable));
262 fastDelete(const_cast<HashTable*>(objectPrototypeTable));
263 fastDelete(const_cast<HashTable*>(regExpTable));
264 fastDelete(const_cast<HashTable*>(regExpConstructorTable));
265 fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
266 fastDelete(const_cast<HashTable*>(stringTable));
267 fastDelete(const_cast<HashTable*>(stringConstructorTable));
268
269 opaqueJSClassData.clear();
270
271 delete emptyList;
272
273 delete propertyNames;
274 if (globalDataType != Default)
275 deleteIdentifierTable(identifierTable);
276
277 delete clientData;
278 delete m_regExpCache;
279 #if ENABLE(REGEXP_TRACING)
280 delete m_rtTraceList;
281 #endif
282
283 #if ENABLE(DFG_JIT)
284 for (unsigned i = 0; i < scratchBuffers.size(); ++i)
285 fastFree(scratchBuffers[i]);
286 #endif
287 }
288
289 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type, HeapSize heapSize)
290 {
291 return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize));
292 }
293
294 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapSize heapSize)
295 {
296 return adoptRef(new JSGlobalData(Default, type, heapSize));
297 }
298
299 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize)
300 {
301 return create(type, heapSize);
302 }
303
304 bool JSGlobalData::sharedInstanceExists()
305 {
306 return sharedInstanceInternal();
307 }
308
309 JSGlobalData& JSGlobalData::sharedInstance()
310 {
311 GlobalJSLock globalLock;
312 JSGlobalData*& instance = sharedInstanceInternal();
313 if (!instance) {
314 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
315 instance->makeUsableFromMultipleThreads();
316 }
317 return *instance;
318 }
319
320 JSGlobalData*& JSGlobalData::sharedInstanceInternal()
321 {
322 static JSGlobalData* sharedInstance;
323 return sharedInstance;
324 }
325
326 #if ENABLE(JIT)
327 static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
328 {
329 switch (intrinsic) {
330 case CharCodeAtIntrinsic:
331 return charCodeAtThunkGenerator;
332 case CharAtIntrinsic:
333 return charAtThunkGenerator;
334 case FromCharCodeIntrinsic:
335 return fromCharCodeThunkGenerator;
336 case SqrtIntrinsic:
337 return sqrtThunkGenerator;
338 case PowIntrinsic:
339 return powThunkGenerator;
340 case AbsIntrinsic:
341 return absThunkGenerator;
342 case FloorIntrinsic:
343 return floorThunkGenerator;
344 case CeilIntrinsic:
345 return ceilThunkGenerator;
346 case RoundIntrinsic:
347 return roundThunkGenerator;
348 case ExpIntrinsic:
349 return expThunkGenerator;
350 case LogIntrinsic:
351 return logThunkGenerator;
352 default:
353 return 0;
354 }
355 }
356
357 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
358 {
359 #if ENABLE(CLASSIC_INTERPRETER)
360 if (!canUseJIT())
361 return NativeExecutable::create(*this, function, constructor);
362 #endif
363 return jitStubs->hostFunctionStub(this, function, constructor);
364 }
365 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic)
366 {
367 ASSERT(canUseJIT());
368 return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
369 }
370 #else
371 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
372 {
373 return NativeExecutable::create(*this, function, constructor);
374 }
375 #endif
376
377 JSGlobalData::ClientData::~ClientData()
378 {
379 }
380
381 void JSGlobalData::resetDateCache()
382 {
383 cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
384 dstOffsetCache.reset();
385 cachedDateString = UString();
386 cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
387 dateInstanceCache.reset();
388 }
389
390 void JSGlobalData::startSampling()
391 {
392 interpreter->startSampling();
393 }
394
395 void JSGlobalData::stopSampling()
396 {
397 interpreter->stopSampling();
398 }
399
400 void JSGlobalData::dumpSampleData(ExecState* exec)
401 {
402 interpreter->dumpSampleData(exec);
403 #if ENABLE(ASSEMBLER)
404 ExecutableAllocator::dumpProfile();
405 #endif
406 }
407
408 struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
409 HashSet<FunctionExecutable*> currentlyExecutingFunctions;
410 void operator()(JSCell* cell)
411 {
412 if (!cell->inherits(&FunctionExecutable::s_info))
413 return;
414 FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
415 if (currentlyExecutingFunctions.contains(executable))
416 return;
417 executable->discardCode();
418 }
419 };
420
421 void JSGlobalData::releaseExecutableMemory()
422 {
423 if (dynamicGlobalObject) {
424 StackPreservingRecompiler recompiler;
425 HashSet<JSCell*> roots;
426 heap.getConservativeRegisterRoots(roots);
427 HashSet<JSCell*>::iterator end = roots.end();
428 for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
429 ScriptExecutable* executable = 0;
430 JSCell* cell = *ptr;
431 if (cell->inherits(&ScriptExecutable::s_info))
432 executable = static_cast<ScriptExecutable*>(*ptr);
433 else if (cell->inherits(&JSFunction::s_info)) {
434 JSFunction* function = jsCast<JSFunction*>(*ptr);
435 if (function->isHostFunction())
436 continue;
437 executable = function->jsExecutable();
438 } else
439 continue;
440 ASSERT(executable->inherits(&ScriptExecutable::s_info));
441 executable->unlinkCalls();
442 if (executable->inherits(&FunctionExecutable::s_info))
443 recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
444
445 }
446 heap.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler);
447 }
448 m_regExpCache->invalidateCode();
449 heap.collectAllGarbage();
450 }
451
452 #if ENABLE(ASSEMBLER)
453 void releaseExecutableMemory(JSGlobalData& globalData)
454 {
455 globalData.releaseExecutableMemory();
456 }
457 #endif
458
459 #if ENABLE(DFG_JIT)
460 void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
461 {
462 for (size_t i = 0; i < scratchBuffers.size(); i++) {
463 ScratchBuffer* scratchBuffer = scratchBuffers[i];
464 if (scratchBuffer->activeLength()) {
465 void* bufferStart = scratchBuffer->dataBuffer();
466 conservativeRoots.add(bufferStart, static_cast<void*>(static_cast<char*>(bufferStart) + scratchBuffer->activeLength()));
467 }
468 }
469 }
470 #endif
471
472 #if ENABLE(REGEXP_TRACING)
473 void JSGlobalData::addRegExpToTrace(RegExp* regExp)
474 {
475 m_rtTraceList->add(regExp);
476 }
477
478 void JSGlobalData::dumpRegExpTrace()
479 {
480 // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
481 RTTraceList::iterator iter = ++m_rtTraceList->begin();
482
483 if (iter != m_rtTraceList->end()) {
484 dataLog("\nRegExp Tracing\n");
485 dataLog(" match() matches\n");
486 dataLog("Regular Expression JIT Address calls found\n");
487 dataLog("----------------------------------------+----------------+----------+----------\n");
488
489 unsigned reCount = 0;
490
491 for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
492 (*iter)->printTraceData();
493
494 dataLog("%d Regular Expressions\n", reCount);
495 }
496
497 m_rtTraceList->clear();
498 }
499 #else
500 void JSGlobalData::dumpRegExpTrace()
501 {
502 }
503 #endif
504
505 } // namespace JSC