source: webkit/trunk/JavaScriptCore/runtime/JSGlobalData.cpp@ 52040

Last change on this file since 52040 was 52040, checked in by [email protected], 15 years ago

JavaScriptCore: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

Added WeakGCMap to keep WebCore blissfully ignorant about objects that
have become garbage but haven't run their destructors yet.

1% SunSpider speedup.
7.6% v8 speedup (37% splay speedup).
17% speedup on bench-alloc-nonretained.js.
18% speedup on bench-alloc-retained.js.

  • API/JSBase.cpp:

(JSGarbageCollect):

files.

  • debugger/Debugger.cpp:

(JSC::Debugger::recompileAllJSFunctions): Updated to use the Collector
iterator abstraction.

  • jsc.cpp:

(functionGC): Updated for rename.

  • runtime/Collector.cpp: Slightly reduced the number of allocations per

collection, so that small workloads only allocate on collector block,
rather than two.

(JSC::Heap::Heap): Updated to use the new allocateBlock function.

(JSC::Heap::destroy): Updated to use the new freeBlocks function.

(JSC::Heap::allocateBlock): New function to initialize a block when
allocating it.

(JSC::Heap::freeBlock): Consolidated the responsibility for running
destructors into this function.

(JSC::Heap::freeBlocks): Updated to use freeBlock.

(JSC::Heap::recordExtraCost): Sweep the heap in this reporting function,
so that allocation, which is more common, doesn't have to check extraCost.

(JSC::Heap::heapAllocate): Run destructors right before recycling a
garbage cell. This has better cache utilization than a separate sweep phase.

(JSC::Heap::resizeBlocks):
(JSC::Heap::growBlocks):
(JSC::Heap::shrinkBlocks): New set of functions for managing the size of
the heap, now that the heap doesn't maintain any information about its
size.

(JSC::isPointerAligned):
(JSC::isHalfCellAligned):
(JSC::isPossibleCell):
(JSC::isCellAligned):
(JSC::Heap::markConservatively): Cleaned up this code a bit.

(JSC::Heap::clearMarkBits):
(JSC::Heap::markedCells): Some helper functions for examining the the mark
bitmap.

(JSC::Heap::sweep): Simplified this function by using a DeadObjectIterator.

(JSC::Heap::markRoots): Reordered some operations for clarity.

(JSC::Heap::objectCount):
(JSC::Heap::addToStatistics):
(JSC::Heap::statistics): Rewrote these functions to calculate an object
count on demand, since the heap doesn't maintain this information by
itself.

(JSC::Heap::reset): New function for resetting the heap once we've
exhausted heap space.

(JSC::Heap::collectAllGarbage): This function matches the old collect()
behavior, but it's now an uncommon function used only by API.

  • runtime/Collector.h:

(JSC::CollectorBitmap::count):
(JSC::CollectorBitmap::isEmpty): Added some helper functions for managing
the collector mark bitmap.

(JSC::Heap::reportExtraMemoryCost): Changed reporting from cell equivalents
to bytes, so it's easier to understand.

  • runtime/CollectorHeapIterator.h:

(JSC::CollectorHeapIterator::CollectorHeapIterator):
(JSC::CollectorHeapIterator::operator!=):
(JSC::CollectorHeapIterator::operator*):
(JSC::CollectorHeapIterator::advance):
(JSC::::LiveObjectIterator):
(JSC::::operator):
(JSC::::DeadObjectIterator):
(JSC::::ObjectIterator): New iterators for encapsulating details about
heap layout, and what's live and dead on the heap.

  • runtime/JSArray.cpp:

(JSC::JSArray::putSlowCase):
(JSC::JSArray::increaseVectorLength): Delay reporting extra cost until
we're fully constructed, so the heap mark phase won't visit us in an
invalid state.

  • runtime/JSCell.h:

(JSC::JSCell::):
(JSC::JSCell::createDummyStructure):
(JSC::JSCell::JSCell):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h: Added a dummy cell to simplify allocation logic.
  • runtime/JSString.h:

(JSC::jsSubstring): Don't report extra cost for substrings, since they
share a buffer that's already reported extra cost.

  • runtime/Tracing.d:
  • runtime/Tracing.h: Changed these dtrace hooks not to report object

counts, since they're no longer cheap to compute.

  • runtime/UString.h: Updated for renames.
  • runtime/WeakGCMap.h: Added.

(JSC::WeakGCMap::isEmpty):
(JSC::WeakGCMap::uncheckedGet):
(JSC::WeakGCMap::uncheckedBegin):
(JSC::WeakGCMap::uncheckedEnd):
(JSC::::get):
(JSC::::take):
(JSC::::set):
(JSC::::uncheckedRemove): Mentioned above.

  • wtf/StdLibExtras.h:

(WTF::bitCount): Added a bit population count function, so the heap can
count live objects to fulfill statistics questions.

JavaScriptGlue: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

  • JavaScriptGlue.cpp:

(JSCollect): Updated for rename. Fixed a bug where JSGlue would not check
to avoid nested GC calls.

WebCore: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

  • ForwardingHeaders/runtime/WeakGCMap.h: Added.
  • bindings/js/GCController.cpp:

(WebCore::collect):
(WebCore::GCController::gcTimerFired):
(WebCore::GCController::garbageCollectNow): Updated for rename.

  • bindings/js/JSDOMBinding.cpp:

(WebCore::removeWrappers):
(WebCore::hasCachedDOMObjectWrapperUnchecked):
(WebCore::hasCachedDOMObjectWrapper):
(WebCore::hasCachedDOMNodeWrapperUnchecked):
(WebCore::forgetDOMObject):
(WebCore::forgetDOMNode):
(WebCore::isObservableThroughDOM):
(WebCore::markDOMNodesForDocument):
(WebCore::markDOMObjectWrapper):
(WebCore::markDOMNodeWrapper):

  • bindings/js/JSDOMBinding.h: Changed DOM wrapper maps to be WeakGCMaps.

Don't ASSERT that an item must be in the WeakGCMap when its destructor
runs, since it might have been overwritten in the map first.

  • bindings/js/JSDocumentCustom.cpp:

(WebCore::toJS): Changed Document from a DOM object wrapper to a DOM node
wrapper, to simplify some code.

  • bindings/js/JSInspectedObjectWrapper.cpp:

(WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
(WebCore::JSInspectedObjectWrapper::~JSInspectedObjectWrapper):

  • bindings/js/JSInspectorCallbackWrapper.cpp: Use a WeakGCMap for these

wrappers.

  • bindings/js/JSNodeCustom.cpp:

(WebCore::JSNode::markChildren): Updated for WeakGCMap and Document using
a DOM node wrapper instead of a DOM object wrapper.

  • bindings/js/JSSVGPODTypeWrapper.h:

(WebCore::JSSVGDynamicPODTypeWrapperCache::wrapperMap):
(WebCore::JSSVGDynamicPODTypeWrapperCache::lookupOrCreateWrapper):
(WebCore::JSSVGDynamicPODTypeWrapperCache::forgetWrapper):
(WebCore::::~JSSVGDynamicPODTypeWrapper): Shined a small beam of sanity
on this code. Use hashtable-based lookup in JSSVGPODTypeWrapper.h instead
of linear lookup through iteration, since that's what hashtables were
invented for. Make JSSVGPODTypeWrapper.h responsible for reomving itself
from the table, instead of its JS wrapper, to decouple these objects from
GC, and because these objects are refCounted, not solely owned by their
JS wrappers.

  • bindings/scripts/CodeGeneratorJS.pm:
  • dom/Document.h: Adopted changes above.
  • Property svn:eol-style set to native
File size: 9.2 KB
Line 
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 "Collector.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 "Parser.h"
49#include "Lexer.h"
50#include "Lookup.h"
51#include "Nodes.h"
52
53#if ENABLE(JSC_MULTIPLE_THREADS)
54#include <wtf/Threading.h>
55#endif
56
57#if PLATFORM(MAC)
58#include "ProfilerServer.h"
59#endif
60
61using namespace WTF;
62
63namespace JSC {
64
65extern JSC_CONST_HASHTABLE HashTable arrayTable;
66extern JSC_CONST_HASHTABLE HashTable jsonTable;
67extern JSC_CONST_HASHTABLE HashTable dateTable;
68extern JSC_CONST_HASHTABLE HashTable mathTable;
69extern JSC_CONST_HASHTABLE HashTable numberTable;
70extern JSC_CONST_HASHTABLE HashTable regExpTable;
71extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
72extern JSC_CONST_HASHTABLE HashTable stringTable;
73
74struct VPtrSet {
75 VPtrSet();
76
77 void* jsArrayVPtr;
78 void* jsByteArrayVPtr;
79 void* jsStringVPtr;
80 void* jsFunctionVPtr;
81};
82
83VPtrSet::VPtrSet()
84{
85 CollectorCell cell;
86 void* storage = &cell;
87
88 COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell);
89 JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
90 jsArrayVPtr = jsArray->vptr();
91 jsArray->~JSCell();
92
93 COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell);
94 JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
95 jsByteArrayVPtr = jsByteArray->vptr();
96 jsByteArray->~JSCell();
97
98 COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell);
99 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
100 jsStringVPtr = jsString->vptr();
101 jsString->~JSCell();
102
103 COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell);
104 JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
105 jsFunctionVPtr = jsFunction->vptr();
106 jsFunction->~JSCell();
107}
108
109JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
110 : isSharedInstance(isShared)
111 , clientData(0)
112 , arrayTable(fastNew<HashTable>(JSC::arrayTable))
113 , dateTable(fastNew<HashTable>(JSC::dateTable))
114 , jsonTable(fastNew<HashTable>(JSC::jsonTable))
115 , mathTable(fastNew<HashTable>(JSC::mathTable))
116 , numberTable(fastNew<HashTable>(JSC::numberTable))
117 , regExpTable(fastNew<HashTable>(JSC::regExpTable))
118 , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
119 , stringTable(fastNew<HashTable>(JSC::stringTable))
120 , activationStructure(JSActivation::createStructure(jsNull()))
121 , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull()))
122 , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
123 , stringStructure(JSString::createStructure(jsNull()))
124 , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull()))
125 , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
126 , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
127 , getterSetterStructure(GetterSetter::createStructure(jsNull()))
128 , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
129 , dummyMarkableCellStructure(JSCell::createDummyStructure())
130#if USE(JSVALUE32)
131 , numberStructure(JSNumberCell::createStructure(jsNull()))
132#endif
133 , jsArrayVPtr(vptrSet.jsArrayVPtr)
134 , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr)
135 , jsStringVPtr(vptrSet.jsStringVPtr)
136 , jsFunctionVPtr(vptrSet.jsFunctionVPtr)
137 , identifierTable(createIdentifierTable())
138 , propertyNames(new CommonIdentifiers(this))
139 , emptyList(new MarkedArgumentBuffer)
140 , lexer(new Lexer(this))
141 , parser(new Parser)
142 , interpreter(new Interpreter)
143#if ENABLE(JIT)
144 , jitStubs(this)
145#endif
146 , heap(this)
147 , initializingLazyNumericCompareFunction(false)
148 , head(0)
149 , dynamicGlobalObject(0)
150 , functionCodeBlockBeingReparsed(0)
151 , firstStringifierToMark(0)
152 , markStack(vptrSet.jsArrayVPtr)
153 , cachedUTCOffset(NaN)
154 , weakRandom(static_cast<int>(currentTime()))
155#ifndef NDEBUG
156 , mainThreadOnly(false)
157#endif
158{
159#if PLATFORM(MAC)
160 startProfilerServerIfNeeded();
161#endif
162}
163
164JSGlobalData::~JSGlobalData()
165{
166 // By the time this is destroyed, heap.destroy() must already have been called.
167
168 delete interpreter;
169#ifndef NDEBUG
170 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
171 interpreter = 0;
172#endif
173
174 arrayTable->deleteTable();
175 dateTable->deleteTable();
176 jsonTable->deleteTable();
177 mathTable->deleteTable();
178 numberTable->deleteTable();
179 regExpTable->deleteTable();
180 regExpConstructorTable->deleteTable();
181 stringTable->deleteTable();
182
183 fastDelete(const_cast<HashTable*>(arrayTable));
184 fastDelete(const_cast<HashTable*>(dateTable));
185 fastDelete(const_cast<HashTable*>(jsonTable));
186 fastDelete(const_cast<HashTable*>(mathTable));
187 fastDelete(const_cast<HashTable*>(numberTable));
188 fastDelete(const_cast<HashTable*>(regExpTable));
189 fastDelete(const_cast<HashTable*>(regExpConstructorTable));
190 fastDelete(const_cast<HashTable*>(stringTable));
191
192 delete parser;
193 delete lexer;
194
195 deleteAllValues(opaqueJSClassData);
196
197 delete emptyList;
198
199 delete propertyNames;
200 deleteIdentifierTable(identifierTable);
201
202 delete clientData;
203}
204
205PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared)
206{
207 return adoptRef(new JSGlobalData(isShared, VPtrSet()));
208}
209
210PassRefPtr<JSGlobalData> JSGlobalData::createLeaked()
211{
212 Structure::startIgnoringLeaks();
213 RefPtr<JSGlobalData> data = create();
214 Structure::stopIgnoringLeaks();
215 return data.release();
216}
217
218bool JSGlobalData::sharedInstanceExists()
219{
220 return sharedInstanceInternal();
221}
222
223JSGlobalData& JSGlobalData::sharedInstance()
224{
225 JSGlobalData*& instance = sharedInstanceInternal();
226 if (!instance) {
227 instance = create(true).releaseRef();
228#if ENABLE(JSC_MULTIPLE_THREADS)
229 instance->makeUsableFromMultipleThreads();
230#endif
231 }
232 return *instance;
233}
234
235JSGlobalData*& JSGlobalData::sharedInstanceInternal()
236{
237 ASSERT(JSLock::currentThreadIsHoldingLock());
238 static JSGlobalData* sharedInstance;
239 return sharedInstance;
240}
241
242// FIXME: We can also detect forms like v1 < v2 ? -1 : 0, reverse comparison, etc.
243const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec)
244{
245 if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) {
246 initializingLazyNumericCompareFunction = true;
247 RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0);
248 lazyNumericCompareFunction = function->bytecode(exec, exec->scopeChain()).instructions();
249 initializingLazyNumericCompareFunction = false;
250 }
251
252 return lazyNumericCompareFunction;
253}
254
255JSGlobalData::ClientData::~ClientData()
256{
257}
258
259void JSGlobalData::resetDateCache()
260{
261 cachedUTCOffset = NaN;
262 dstOffsetCache.reset();
263 cachedDateString = UString();
264 dateInstanceCache.reset();
265}
266
267void JSGlobalData::startSampling()
268{
269 interpreter->startSampling();
270}
271
272void JSGlobalData::stopSampling()
273{
274 interpreter->stopSampling();
275}
276
277void JSGlobalData::dumpSampleData(ExecState* exec)
278{
279 interpreter->dumpSampleData(exec);
280}
281
282} // namespace JSC
Note: See TracBrowser for help on using the repository browser.