source: webkit/trunk/JavaScriptCore/kjs/JSGlobalObject.cpp@ 34907

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

2008-06-30 Geoffrey Garen <[email protected]>

Reviewed by Oliver Hunt.


Fixed a global object leak caused by the switch to one register file.


Don't unconditionally mark the register file, since that logically
makes all global variables GC roots, even when their global object is
no longer reachable.


Instead, make the global object associated with the register file
responsible for marking the register file.

  • Property svn:eol-style set to native
File size: 19.0 KB
Line 
1/*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich ([email protected])
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "JSGlobalObject.h"
32
33#include "ArrayConstructor.h"
34#include "ArrayPrototype.h"
35#include "BooleanConstructor.h"
36#include "BooleanPrototype.h"
37#include "CodeBlock.h"
38#include "DateConstructor.h"
39#include "DatePrototype.h"
40#include "ErrorConstructor.h"
41#include "ErrorPrototype.h"
42#include "FunctionConstructor.h"
43#include "FunctionPrototype.h"
44#include "Machine.h"
45#include "MathObject.h"
46#include "NativeErrorConstructor.h"
47#include "NativeErrorPrototype.h"
48#include "NumberConstructor.h"
49#include "NumberPrototype.h"
50#include "ObjectConstructor.h"
51#include "ObjectPrototype.h"
52#include "RegExpConstructor.h"
53#include "RegExpPrototype.h"
54#include "ScopeChainMark.h"
55#include "StringConstructor.h"
56#include "StringPrototype.h"
57#include "debugger.h"
58
59namespace KJS {
60
61// Default number of ticks before a timeout check should be done.
62static const int initialTickCountThreshold = 255;
63
64// Preferred number of milliseconds between each timeout check
65static const int preferredScriptCheckTimeInterval = 1000;
66
67static inline void markIfNeeded(JSValue* v)
68{
69 if (v && !v->marked())
70 v->mark();
71}
72
73JSGlobalObject::~JSGlobalObject()
74{
75 ASSERT(JSLock::currentThreadIsHoldingLock());
76
77 if (d()->debugger)
78 d()->debugger->detach(this);
79
80 d()->next->d()->prev = d()->prev;
81 d()->prev->d()->next = d()->next;
82 JSGlobalObject*& headObject = head();
83 if (headObject == this)
84 headObject = d()->next;
85 if (headObject == this)
86 headObject = 0;
87
88 HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end();
89 for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it)
90 (*it)->globalObject = 0;
91
92 RegisterFile& registerFile = globalData()->machine->registerFile();
93 if (registerFile.globalObject() == this) {
94 registerFile.setGlobalObject(0);
95 registerFile.setNumGlobals(0);
96 }
97 delete d();
98}
99
100void JSGlobalObject::init(JSObject* thisValue)
101{
102 ASSERT(JSLock::currentThreadIsHoldingLock());
103
104 d()->globalData = (Heap::heap(this) == JSGlobalData::sharedInstance().heap) ? &JSGlobalData::sharedInstance() : &JSGlobalData::threadInstance();
105
106 if (JSGlobalObject*& headObject = head()) {
107 d()->prev = headObject;
108 d()->next = headObject->d()->next;
109 headObject->d()->next->d()->prev = this;
110 headObject->d()->next = this;
111 } else
112 headObject = d()->next = d()->prev = this;
113
114 d()->recursion = 0;
115 d()->debugger = 0;
116 globalData()->machine->initTimeout();
117
118 d()->globalExec.set(new ExecState(this, thisValue, d()->globalScopeChain.node()));
119
120 d()->pageGroupIdentifier = 0;
121
122 reset(prototype());
123}
124
125void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
126{
127 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
128
129 if (symbolTablePut(propertyName, value))
130 return;
131 return JSVariableObject::put(exec, propertyName, value);
132}
133
134void JSGlobalObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue* value, unsigned attributes)
135{
136 if (symbolTablePutWithAttributes(propertyName, value, attributes))
137 return;
138
139 JSValue* valueBefore = getDirect(propertyName);
140 JSVariableObject::put(exec, propertyName, value);
141 if (!valueBefore) {
142 if (JSValue* valueAfter = getDirect(propertyName))
143 putDirect(propertyName, valueAfter, attributes);
144 }
145}
146
147void JSGlobalObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc)
148{
149 PropertySlot slot;
150 if (!symbolTableGet(propertyName, slot))
151 JSVariableObject::defineGetter(exec, propertyName, getterFunc);
152}
153
154void JSGlobalObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc)
155{
156 PropertySlot slot;
157 if (!symbolTableGet(propertyName, slot))
158 JSVariableObject::defineSetter(exec, propertyName, setterFunc);
159}
160
161static inline JSObject* lastInPrototypeChain(JSObject* object)
162{
163 JSObject* o = object;
164 while (o->prototype()->isObject())
165 o = static_cast<JSObject*>(o->prototype());
166 return o;
167}
168
169void JSGlobalObject::reset(JSValue* prototype)
170{
171 // Clear before inititalizing, to avoid calling mark() on stale pointers --
172 // which would be wasteful -- or uninitialized pointers -- which would be
173 // dangerous. (The allocations below may cause a GC.)
174
175 _prop.clear();
176 symbolTable().clear();
177
178 // Prototypes
179 d()->functionPrototype = 0;
180 d()->objectPrototype = 0;
181
182 d()->arrayPrototype = 0;
183 d()->stringPrototype = 0;
184 d()->booleanPrototype = 0;
185 d()->numberPrototype = 0;
186 d()->datePrototype = 0;
187 d()->regExpPrototype = 0;
188 d()->errorPrototype = 0;
189
190 d()->evalErrorPrototype = 0;
191 d()->rangeErrorPrototype = 0;
192 d()->referenceErrorPrototype = 0;
193 d()->syntaxErrorPrototype = 0;
194 d()->typeErrorPrototype = 0;
195 d()->URIErrorPrototype = 0;
196
197 // Constructors
198 d()->regExpConstructor = 0;
199 d()->errorConstructor = 0;
200
201 d()->evalErrorConstructor = 0;
202 d()->rangeErrorConstructor = 0;
203 d()->referenceErrorConstructor = 0;
204 d()->syntaxErrorConstructor = 0;
205 d()->typeErrorConstructor = 0;
206 d()->URIErrorConstructor = 0;
207
208 d()->evalFunction = 0;
209
210 ExecState* exec = d()->globalExec.get();
211
212 // Prototypes
213
214 d()->functionPrototype = new (exec) FunctionPrototype(exec);
215 d()->objectPrototype = new (exec) ObjectPrototype(exec, d()->functionPrototype);
216 d()->functionPrototype->setPrototype(d()->objectPrototype);
217
218 d()->arrayPrototype = new (exec) ArrayPrototype(exec, d()->objectPrototype);
219 d()->stringPrototype = new (exec) StringPrototype(exec, d()->objectPrototype);
220 d()->booleanPrototype = new (exec) BooleanPrototype(exec, d()->objectPrototype, d()->functionPrototype);
221 d()->numberPrototype = new (exec) NumberPrototype(exec, d()->objectPrototype, d()->functionPrototype);
222 d()->datePrototype = new (exec) DatePrototype(exec, d()->objectPrototype);
223 d()->regExpPrototype = new (exec) RegExpPrototype(exec, d()->objectPrototype, d()->functionPrototype);
224 d()->errorPrototype = new (exec) ErrorPrototype(exec, d()->objectPrototype, d()->functionPrototype);
225
226 d()->evalErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "EvalError", "EvalError");
227 d()->rangeErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "RangeError", "RangeError");
228 d()->referenceErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "ReferenceError", "ReferenceError");
229 d()->syntaxErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "SyntaxError", "SyntaxError");
230 d()->typeErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "TypeError", "TypeError");
231 d()->URIErrorPrototype = new (exec) NativeErrorPrototype(exec, d()->errorPrototype, "URIError", "URIError");
232
233 // Constructors
234
235 JSValue* objectConstructor = new (exec) ObjectConstructor(exec, d()->objectPrototype, d()->functionPrototype);
236 JSValue* functionConstructor = new (exec) FunctionConstructor(exec, d()->functionPrototype);
237 JSValue* arrayConstructor = new (exec) ArrayConstructor(exec, d()->functionPrototype, d()->arrayPrototype);
238 JSValue* stringConstructor = new (exec) StringConstructor(exec, d()->functionPrototype, d()->stringPrototype);
239 JSValue* booleanConstructor = new (exec) BooleanConstructor(exec, d()->functionPrototype, d()->booleanPrototype);
240 JSValue* numberConstructor = new (exec) NumberConstructor(exec, d()->functionPrototype, d()->numberPrototype);
241 JSValue* dateConstructor = new (exec) DateConstructor(exec, d()->functionPrototype, d()->datePrototype);
242
243 d()->regExpConstructor = new (exec) RegExpConstructor(exec, d()->functionPrototype, d()->regExpPrototype);
244
245 d()->errorConstructor = new (exec) ErrorConstructor(exec, d()->functionPrototype, d()->errorPrototype);
246
247 d()->evalErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->evalErrorPrototype);
248 d()->rangeErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->rangeErrorPrototype);
249 d()->referenceErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->referenceErrorPrototype);
250 d()->syntaxErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->syntaxErrorPrototype);
251 d()->typeErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->typeErrorPrototype);
252 d()->URIErrorConstructor = new (exec) NativeErrorConstructor(exec, d()->functionPrototype, d()->URIErrorPrototype);
253
254 d()->functionPrototype->putDirect(exec->propertyNames().constructor, functionConstructor, DontEnum);
255
256 d()->objectPrototype->putDirect(exec->propertyNames().constructor, objectConstructor, DontEnum);
257 d()->functionPrototype->putDirect(exec->propertyNames().constructor, functionConstructor, DontEnum);
258 d()->arrayPrototype->putDirect(exec->propertyNames().constructor, arrayConstructor, DontEnum);
259 d()->booleanPrototype->putDirect(exec->propertyNames().constructor, booleanConstructor, DontEnum);
260 d()->stringPrototype->putDirect(exec->propertyNames().constructor, stringConstructor, DontEnum);
261 d()->numberPrototype->putDirect(exec->propertyNames().constructor, numberConstructor, DontEnum);
262 d()->datePrototype->putDirect(exec->propertyNames().constructor, dateConstructor, DontEnum);
263 d()->regExpPrototype->putDirect(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum);
264 d()->errorPrototype->putDirect(exec->propertyNames().constructor, d()->errorConstructor, DontEnum);
265 d()->evalErrorPrototype->putDirect(exec->propertyNames().constructor, d()->evalErrorConstructor, DontEnum);
266 d()->rangeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->rangeErrorConstructor, DontEnum);
267 d()->referenceErrorPrototype->putDirect(exec->propertyNames().constructor, d()->referenceErrorConstructor, DontEnum);
268 d()->syntaxErrorPrototype->putDirect(exec->propertyNames().constructor, d()->syntaxErrorConstructor, DontEnum);
269 d()->typeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->typeErrorConstructor, DontEnum);
270 d()->URIErrorPrototype->putDirect(exec->propertyNames().constructor, d()->URIErrorConstructor, DontEnum);
271
272 // Set global constructors
273
274 // FIXME: These properties could be handled by a static hash table.
275
276 putDirect(Identifier(exec, "Object"), objectConstructor, DontEnum);
277 putDirect(Identifier(exec, "Function"), functionConstructor, DontEnum);
278 putDirect(Identifier(exec, "Array"), arrayConstructor, DontEnum);
279 putDirect(Identifier(exec, "Boolean"), booleanConstructor, DontEnum);
280 putDirect(Identifier(exec, "String"), stringConstructor, DontEnum);
281 putDirect(Identifier(exec, "Number"), numberConstructor, DontEnum);
282 putDirect(Identifier(exec, "Date"), dateConstructor, DontEnum);
283 putDirect(Identifier(exec, "RegExp"), d()->regExpConstructor, DontEnum);
284 putDirect(Identifier(exec, "Error"), d()->errorConstructor, DontEnum);
285 putDirect(Identifier(exec, "EvalError"), d()->evalErrorConstructor);
286 putDirect(Identifier(exec, "RangeError"), d()->rangeErrorConstructor);
287 putDirect(Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor);
288 putDirect(Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor);
289 putDirect(Identifier(exec, "TypeError"), d()->typeErrorConstructor);
290 putDirect(Identifier(exec, "URIError"), d()->URIErrorConstructor);
291
292 // Set global values.
293 GlobalPropertyInfo staticGlobals[] = {
294 GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, d()->objectPrototype), DontEnum | DontDelete),
295 GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete),
296 GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete),
297 GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete)
298 };
299
300 addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
301
302 // Set global functions.
303
304 d()->evalFunction = new (exec) GlobalEvalFunction(exec, d()->functionPrototype, 1, exec->propertyNames().eval, globalFuncEval, this);
305 putDirectFunction(d()->evalFunction, DontEnum);
306 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum);
307 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum);
308 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum);
309 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum);
310 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum);
311 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum);
312 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum);
313 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum);
314 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum);
315 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum);
316#ifndef NDEBUG
317 putDirectFunction(new (exec) PrototypeFunction(exec, d()->functionPrototype, 1, Identifier(exec, "kjsprint"), globalFuncKJSPrint), DontEnum);
318#endif
319
320 // Set prototype, and also insert the object prototype at the end of the chain.
321
322 setPrototype(prototype);
323 lastInPrototypeChain(this)->setPrototype(d()->objectPrototype);
324}
325
326void JSGlobalObject::setTimeoutTime(unsigned timeoutTime)
327{
328 globalData()->machine->setTimeoutTime(timeoutTime);
329}
330
331void JSGlobalObject::startTimeoutCheck()
332{
333 globalData()->machine->startTimeoutCheck();
334}
335
336void JSGlobalObject::stopTimeoutCheck()
337{
338 globalData()->machine->stopTimeoutCheck();
339}
340
341void JSGlobalObject::mark()
342{
343 JSVariableObject::mark();
344
345 HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end();
346 for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it)
347 (*it)->mark();
348
349 RegisterFile& registerFile = globalData()->machine->registerFile();
350 if (registerFile.globalObject() == this)
351 registerFile.mark(globalData()->heap);
352
353 markIfNeeded(d()->globalExec->exception());
354
355 markIfNeeded(d()->regExpConstructor);
356 markIfNeeded(d()->errorConstructor);
357 markIfNeeded(d()->evalErrorConstructor);
358 markIfNeeded(d()->rangeErrorConstructor);
359 markIfNeeded(d()->referenceErrorConstructor);
360 markIfNeeded(d()->syntaxErrorConstructor);
361 markIfNeeded(d()->typeErrorConstructor);
362 markIfNeeded(d()->URIErrorConstructor);
363
364 markIfNeeded(d()->evalFunction);
365
366 markIfNeeded(d()->objectPrototype);
367 markIfNeeded(d()->functionPrototype);
368 markIfNeeded(d()->arrayPrototype);
369 markIfNeeded(d()->booleanPrototype);
370 markIfNeeded(d()->stringPrototype);
371 markIfNeeded(d()->numberPrototype);
372 markIfNeeded(d()->datePrototype);
373 markIfNeeded(d()->regExpPrototype);
374 markIfNeeded(d()->errorPrototype);
375 markIfNeeded(d()->evalErrorPrototype);
376 markIfNeeded(d()->rangeErrorPrototype);
377 markIfNeeded(d()->referenceErrorPrototype);
378 markIfNeeded(d()->syntaxErrorPrototype);
379 markIfNeeded(d()->typeErrorPrototype);
380 markIfNeeded(d()->URIErrorPrototype);
381}
382
383JSGlobalObject* JSGlobalObject::toGlobalObject(ExecState*) const
384{
385 return const_cast<JSGlobalObject*>(this);
386}
387
388ExecState* JSGlobalObject::globalExec()
389{
390 return d()->globalExec.get();
391}
392
393bool JSGlobalObject::isDynamicScope() const
394{
395 return true;
396}
397
398void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile)
399{
400 ASSERT(!d()->registerArray);
401 ASSERT(!d()->registerArraySize);
402
403 int numGlobals = registerFile.numGlobals();
404 if (!numGlobals) {
405 d()->registers = 0;
406 return;
407 }
408 copyRegisterArray(registerFile.lastGlobal(), numGlobals);
409}
410
411void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile)
412{
413 JSGlobalObject* lastGlobalObject = registerFile.globalObject();
414 if (lastGlobalObject && lastGlobalObject != this)
415 lastGlobalObject->copyGlobalsFrom(registerFile);
416
417 registerFile.setGlobalObject(this);
418 registerFile.setNumGlobals(symbolTable().size());
419
420 if (d()->registerArray) {
421 memcpy(registerFile.base() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register));
422 setRegisterArray(0, 0);
423 }
424
425 d()->registers = registerFile.base();
426}
427
428void* JSGlobalObject::operator new(size_t size)
429{
430#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
431 return JSGlobalData::threadInstance().heap->inlineAllocate(size);
432#else
433 return JSGlobalData::threadInstance().heap->allocate(size);
434#endif
435}
436
437void* JSGlobalObject::operator new(size_t size, SharedTag)
438{
439#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
440 return JSGlobalData::sharedInstance().heap->inlineAllocate(size);
441#else
442 return JSGlobalData::sharedInstance().heap->allocate(size);
443#endif
444}
445
446} // namespace KJS
Note: See TracBrowser for help on using the repository browser.