-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Add files missing from previous commit.
-
- * kjs/MarkStack.h: Added.
-
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Not reviewed.
-
- - Fixed "Stack overflow crash in JavaScript garbage collector mark pass"
- http://bugs.webkit.org/show_bug.cgi?id=12216
-
- Implement mark stack. This version is not suitable for prime time because it makes a
- huge allocation on every collect, and potentially makes marking of detached subtrees
- slow. But it is a .2% - .4% speedup even without much tweaking.
-
- The basic approach is to replace mark() methods with
- markChildren(MarkStack&) methods. Reachable references are pushed
- onto a mark stack (which encapsulates ignoring already-marked
- references).
-
- Objects are no longer responsible for actually setting their own
- mark bits, the collector does that. This means that for objects on
- the number heap we don't have to call markChildren() at all since
- we know there aren't any.
-
- The mark phase of collect pushes roots onto the mark stack
- and drains it as often as possible.
-
- To make this approach viable requires a constant-size mark stack
- and a slow fallback approach for when the stack size is exceeded,
- plus optimizations to make the required stack small in common
- cases. This should be doable.
-
- * JavaScriptCore.exp: Export new symbols.
- * JavaScriptCore.xcodeproj/project.pbxproj: Add new file.
- * kjs/collector.cpp:
- (KJS::Collector::heapAllocate):
- (KJS::drainMarkStack): Helper for all of the below.
- (KJS::Collector::markStackObjectsConservatively): Use mark stack.
- (KJS::Collector::markCurrentThreadConservatively): ditto
- (KJS::Collector::markOtherThreadConservatively): ditto
- (KJS::Collector::markProtectedObjects): ditto
- (KJS::Collector::markMainThreadOnlyObjects): ditto
- (KJS::Collector::collect): ditto
- * kjs/collector.h:
- (KJS::Collector::cellMayHaveRefs): Helper for MarkStack.
-
- * kjs/MarkStack.h: Added. The actual mark stack implementation.
- (KJS::MarkStack::push):
- (KJS::MarkStack::pushAtom):
- (KJS::MarkStack::pop):
- (KJS::MarkStack::isEmpty):
- (KJS::MarkStack::reserveCapacity):
-
- Changed mark() methods to markChildren() methods:
-
- * kjs/ExecState.cpp:
- (KJS::ExecState::markChildren):
- * kjs/ExecState.h:
- * kjs/JSWrapperObject.cpp:
- (KJS::JSWrapperObject::markChildren):
- * kjs/JSWrapperObject.h:
- * kjs/array_instance.cpp:
- (KJS::ArrayInstance::markChildren):
- * kjs/array_instance.h:
- * kjs/bool_object.cpp:
- (BooleanInstance::markChildren):
- * kjs/bool_object.h:
- * kjs/error_object.cpp:
- * kjs/error_object.h:
- * kjs/function.cpp:
- (KJS::FunctionImp::markChildren):
- (KJS::Arguments::Arguments):
- (KJS::Arguments::markChildren):
- (KJS::ActivationImp::markChildren):
- * kjs/function.h:
- * kjs/internal.cpp:
- (KJS::GetterSetterImp::markChildren):
- * kjs/interpreter.cpp:
- (KJS::Interpreter::markRoots):
- * kjs/interpreter.h:
- * kjs/list.cpp:
- (KJS::List::markProtectedListsSlowCase):
- * kjs/list.h:
- (KJS::List::markProtectedLists):
- * kjs/object.cpp:
- (KJS::JSObject::markChildren):
- * kjs/object.h:
- (KJS::ScopeChain::markChildren):
- * kjs/property_map.cpp:
- (KJS::PropertyMap::markChildren):
- * kjs/property_map.h:
- * kjs/scope_chain.h:
- * kjs/string_object.cpp:
- (KJS::StringInstance::markChildren):
- * kjs/string_object.h:
-
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Reviewed by Darin and Geoff.
-
- - Fixed "Stack overflow crash in JavaScript garbage collector mark pass"
- http://bugs.webkit.org/show_bug.cgi?id=12216
-
- Implement mark stack. This version is not suitable for prime time because it makes a
- huge allocation on every collect, and potentially makes marking of detached subtrees
- slow. But it is an 0.4% SunSpider speedup even without much tweaking.
-
- The basic approach is to replace mark() methods with
- markChildren(MarkStack&) methods. Reachable references are pushed
- onto a mark stack (which encapsulates ignoring already-marked
- references).
-
- Objects are no longer responsible for actually setting their own
- mark bits, the collector does that. This means that for objects on
- the number heap we don't have to call markChildren() at all since
- we know there aren't any.
-
- The mark phase of collect pushes roots onto the mark stack
- and drains it as often as possible.
-
- To make this approach viable requires a constant-size mark stack
- and a slow fallback approach for when the stack size is exceeded,
- plus optimizations to make the required stack small in common
- cases. This should be doable.
-
- * JavaScriptCore.exp: Export new symbols.
- * JavaScriptCore.xcodeproj/project.pbxproj: Add new file.
- * kjs/collector.cpp:
- (KJS::Collector::heapAllocate):
- (KJS::drainMarkStack): Helper for all of the below.
- (KJS::Collector::markStackObjectsConservatively): Use mark stack.
- (KJS::Collector::markCurrentThreadConservatively): ditto
- (KJS::Collector::markOtherThreadConservatively): ditto
- (KJS::Collector::markProtectedObjects): ditto
- (KJS::Collector::markMainThreadOnlyObjects): ditto
- (KJS::Collector::collect): ditto
- * kjs/collector.h:
- (KJS::Collector::cellMayHaveRefs): Helper for MarkStack.
-
- * kjs/MarkStack.h: Added. The actual mark stack implementation.
- (KJS::MarkStack::push):
- (KJS::MarkStack::pushAtom):
- (KJS::MarkStack::pop):
- (KJS::MarkStack::isEmpty):
- (KJS::MarkStack::reserveCapacity):
-
- Changed mark() methods to markChildren() methods:
-
- * kjs/ExecState.cpp:
- (KJS::ExecState::markChildren):
- * kjs/ExecState.h:
- * kjs/JSWrapperObject.cpp:
- (KJS::JSWrapperObject::markChildren):
- * kjs/JSWrapperObject.h:
- * kjs/array_instance.cpp:
- (KJS::ArrayInstance::markChildren):
- * kjs/array_instance.h:
- * kjs/bool_object.cpp:
- (BooleanInstance::markChildren):
- * kjs/bool_object.h:
- * kjs/error_object.cpp:
- * kjs/error_object.h:
- * kjs/function.cpp:
- (KJS::FunctionImp::markChildren):
- (KJS::Arguments::Arguments):
- (KJS::Arguments::markChildren):
- (KJS::ActivationImp::markChildren):
- * kjs/function.h:
- * kjs/internal.cpp:
- (KJS::GetterSetterImp::markChildren):
- * kjs/interpreter.cpp:
- (KJS::Interpreter::markRoots):
- * kjs/interpreter.h:
- * kjs/list.cpp:
- (KJS::List::markProtectedListsSlowCase):
- * kjs/list.h:
- (KJS::List::markProtectedLists):
- * kjs/object.cpp:
- (KJS::JSObject::markChildren):
- * kjs/object.h:
- (KJS::ScopeChain::markChildren):
- * kjs/property_map.cpp:
- (KJS::PropertyMap::markChildren):
- * kjs/property_map.h:
- * kjs/scope_chain.h:
- * kjs/string_object.cpp:
- (KJS::StringInstance::markChildren):
- * kjs/string_object.h:
-
2007-11-27 Alp Toker <alp@atoker.com>
Reviewed by Mark Rowe.
__ZN3KJS11Interpreter21shouldPrintExceptionsEv
__ZN3KJS11Interpreter24setShouldPrintExceptionsEb
__ZN3KJS11Interpreter27resetGlobalObjectPropertiesEv
+__ZN3KJS11Interpreter4markEv
__ZN3KJS11Interpreter6s_hookE
__ZN3KJS11Interpreter8evaluateERKNS_7UStringEiPKNS_5UCharEiPNS_7JSValueE
__ZN3KJS11Interpreter8evaluateERKNS_7UStringEiS3_PNS_7JSValueE
-__ZN3KJS11Interpreter9markRootsERNS_9MarkStackE
__ZN3KJS11InterpreterC1Ev
__ZN3KJS11InterpreterC2Ev
__ZN3KJS11InterpreterD1Ev
__ZN3KJS13SavedBuiltinsC1Ev
__ZN3KJS13SavedBuiltinsD1Ev
__ZN3KJS13jsOwnedStringERKNS_7UStringE
-__ZN3KJS14StringInstance12markChildrenERNS_9MarkStackE
__ZN3KJS14StringInstance14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS14StringInstance16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS14StringInstance18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3KJS14StringInstance4infoE
__ZN3KJS14StringInstanceC1EPNS_8JSObjectERKNS_7UStringE
__ZN3KJS14StringInstanceC2EPNS_8JSObjectERKNS_7UStringE
+__ZN3KJS15JSWrapperObject4markEv
__ZN3KJS15SavedPropertiesC1Ev
__ZN3KJS15SavedPropertiesD1Ev
__ZN3KJS16RuntimeObjectImp4infoE
__ZN3KJS8DebuggerC2Ev
__ZN3KJS8DebuggerD2Ev
__ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
-__ZN3KJS8JSObject12markChildrenERNS_9MarkStackE
__ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE
__ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE
__ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi
__ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi
__ZN3KJS8JSObject4callEPNS_9ExecStateEPS0_RKNS_4ListE
+__ZN3KJS8JSObject4markEv
__ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListE
__ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListERKNS_10IdentifierERKNS_7UStringEi
__ZN3KJS8JSObject9putDirectERKNS_10IdentifierEPNS_7JSValueEi
6592C318098B7DE10003D4F6 /* Vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 6592C316098B7DE10003D4F6 /* Vector.h */; settings = {ATTRIBUTES = (Private, ); }; };
6592C319098B7DE10003D4F6 /* VectorTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6592C317098B7DE10003D4F6 /* VectorTraits.h */; settings = {ATTRIBUTES = (Private, ); }; };
65A7A5E00CD1D50E00061F8E /* LabelStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B813A80CD1D01900DF59D6 /* LabelStack.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 65A8B8DB0CF408F400DC7C27 /* MarkStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 65A8B8D80CF408E900DC7C27 /* MarkStack.h */; settings = {ATTRIBUTES = (Private, ); }; };
65B1749A09D0FEB700820339 /* array_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B1749909D0FEB700820339 /* array_object.lut.h */; };
65B174F509D100FA00820339 /* math_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B174F109D100FA00820339 /* math_object.lut.h */; };
65B174F609D100FA00820339 /* number_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B174F209D100FA00820339 /* number_object.lut.h */; };
659126BC0BDD1728001921FB /* AllInOneFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AllInOneFile.cpp; sourceTree = "<group>"; };
6592C316098B7DE10003D4F6 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; };
6592C317098B7DE10003D4F6 /* VectorTraits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VectorTraits.h; sourceTree = "<group>"; };
- 65A8B8D80CF408E900DC7C27 /* MarkStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStack.h; sourceTree = "<group>"; };
65B1749909D0FEB700820339 /* array_object.lut.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = array_object.lut.h; path = ../../../../../symroots/Debug/DerivedSources/JavaScriptCore/array_object.lut.h; sourceTree = "<group>"; };
65B174BE09D1000200820339 /* chartables.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; path = chartables.c; sourceTree = "<group>"; };
65B174F109D100FA00820339 /* math_object.lut.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = math_object.lut.h; path = ../../../../../symroots/Debug/DerivedSources/JavaScriptCore/math_object.lut.h; sourceTree = "<group>"; };
F692A8680255597D01FF60F7 /* lookup.cpp */,
F692A8690255597D01FF60F7 /* lookup.h */,
F692A86A0255597D01FF60F7 /* math_object.cpp */,
- 65A8B8D80CF408E900DC7C27 /* MarkStack.h */,
F692A86B0255597D01FF60F7 /* math_object.h */,
F692A86D0255597D01FF60F7 /* nodes.cpp */,
F692A86E0255597D01FF60F7 /* nodes.h */,
148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */,
65F340940CD6C1C000C0CA8B /* LocalStorage.h in Headers */,
5DBD18B00C5401A700C15EAE /* MallocZoneSupport.h in Headers */,
- 65A8B8DB0CF408F400DC7C27 /* MarkStack.h in Headers */,
BCF655590A2049710038A194 /* MathExtras.h in Headers */,
932F5B840822A1C700736975 /* NP_jsobject.h in Headers */,
9303F56A0991190000AD71B8 /* Noncopyable.h in Headers */,
m_interpreter->setCurrentExec(m_savedExecState);
}
-void ExecState::markChildren(MarkStack& stack)
+void ExecState::mark()
{
for (ExecState* exec = this; exec; exec = exec->m_callingExecState)
- exec->m_scopeChain.markChildren(stack);
+ exec->m_scopeChain.mark();
}
void ExecState::setGlobalObject(JSGlobalObject* globalObject)
void setGlobalObject(JSGlobalObject*);
- void markChildren(MarkStack&);
+ void mark();
// This is a workaround to avoid accessing the global variables for these identifiers in
// important property lookup functions, to avoid taking PIC branches in Mach-O binaries
namespace KJS {
-void JSWrapperObject::markChildren(MarkStack& stack)
+void JSWrapperObject::mark()
{
- JSObject::markChildren(stack);
- stack.pushAtom(m_internalValue);
+ JSObject::mark();
+ if (m_internalValue && !m_internalValue->marked())
+ m_internalValue->mark();
}
} // namespace KJS
*/
void setInternalValue(JSValue* v);
- virtual void markChildren(MarkStack& stack);
+ virtual void mark();
private:
JSValue* m_internalValue;
inline JSWrapperObject::JSWrapperObject(JSValue* proto)
: JSObject(proto)
- , m_internalValue(jsNull())
+ , m_internalValue(0)
{
}
+++ /dev/null
-// -*- mode: c++; c-basic-offset: 4 -*-
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef MarkStack_h
-#define MarkStack_h
-
-#include <wtf/Vector.h>
-#include "collector.h"
-#include "value.h"
-#include <stdio.h>
-
-namespace KJS {
-
- class MarkStack {
- public:
- void push(JSValue* value)
- {
- if (value->marked())
- return;
- JSCell* cell = value->asCell();
- Collector::markCell(cell);
- if (!Collector::cellMayHaveRefs(cell))
- return;
- ASSERT(m_stack.size() < m_stack.capacity());
- m_stack.uncheckedAppend(cell);
- }
-
- void push(JSCell* cell)
- {
- if (cell->marked())
- return;
- Collector::markCell(cell);
- if (!Collector::cellMayHaveRefs(cell))
- return;
- ASSERT(m_stack.size() < m_stack.capacity());
- m_stack.uncheckedAppend(cell);
- }
-
- void pushAtom(JSValue* value)
- {
- if (value->marked())
- return;
- JSCell* cell = value->asCell();
- Collector::markCell(cell);
- }
-
- void pushAtom(JSCell* cell)
- {
- if (cell->marked())
- return;
- Collector::markCell(cell);
- }
-
- JSCell* pop()
- {
- ASSERT(m_stack.size() > 0);
- JSCell* cell = m_stack.last();
- m_stack.removeLast();
- return cell;
- }
-
- bool isEmpty()
- {
- return m_stack.isEmpty();
- }
-
- void reserveCapacity(size_t size)
- {
- m_stack.reserveCapacity(size);
- }
-
- private:
- Vector<JSCell*> m_stack;
- };
-
-}
-
-#endif // MarkStack_h
m_length = newLength;
}
-void ArrayInstance::markChildren(MarkStack& stack)
+void ArrayInstance::mark()
{
- JSObject::markChildren(stack);
+ JSObject::mark();
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) {
JSValue* value = storage->m_vector[i];
- if (value)
- stack.push(value);
+ if (value && !value->marked())
+ value->mark();
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
- for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
- stack.push(it->second);
+ for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {
+ JSValue* value = it->second;
+ if (!value->marked())
+ value->mark();
+ }
}
}
virtual bool deleteProperty(ExecState *, unsigned propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
- virtual void markChildren(MarkStack&);
+ virtual void mark();
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
{
}
-void BooleanInstance::markChildren(MarkStack& stack)
-{
- JSObject::markChildren(stack);
- ASSERT(JSImmediate::isImmediate(internalValue()));
-}
-
// ------------------------------ BooleanPrototype --------------------------
// ECMA 15.6.4
BooleanInstance(JSObject *proto);
virtual const ClassInfo *classInfo() const { return &info; }
- virtual void markChildren(MarkStack& stack);
static const ClassInfo info;
};
#include "ExecState.h"
#include "internal.h"
#include "list.h"
-#include "MarkStack.h"
#include "value.h"
#include <algorithm>
#include <setjmp.h>
targetBlock = (Block*)allocateBlock();
targetBlock->freeList = targetBlock->cells;
- if (heapType == PrimaryHeap)
- targetBlock->mayHaveRefs = 1;
targetBlockUsedCells = 0;
heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock;
heap.usedBlocks = usedBlocks + 1;
// cell size needs to be a power of two for this to be valid
#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
-static inline void drainMarkStack(MarkStack& stack)
-{
- while (!stack.isEmpty())
- stack.pop()->markChildren(stack);
-}
-
-
-void Collector::markStackObjectsConservatively(MarkStack& stack, void *start, void *end)
+void Collector::markStackObjectsConservatively(void *start, void *end)
{
if (start > end) {
void* tmp = start;
if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) {
JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
- stack.push(imp);
- drainMarkStack(stack);
+ if (!imp->marked())
+ imp->mark();
}
break;
}
}
}
-void Collector::markCurrentThreadConservatively(MarkStack& stack)
+void Collector::markCurrentThreadConservatively()
{
// setjmp forces volatile registers onto the stack
jmp_buf registers;
void* stackPointer = &dummy;
void* stackBase = currentThreadStackBase();
- markStackObjectsConservatively(stack, stackPointer, stackBase);
+ markStackObjectsConservatively(stackPointer, stackBase);
}
#if USE(MULTIPLE_THREADS)
#endif
}
-void Collector::markOtherThreadConservatively(MarkStack& stack, Thread* thread)
+void Collector::markOtherThreadConservatively(Thread* thread)
{
suspendThread(thread->platformThread);
size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
// mark the thread's registers
- markStackObjectsConservatively(stack, (void*)®s, (void*)((char*)®s + regSize));
+ markStackObjectsConservatively((void*)®s, (void*)((char*)®s + regSize));
void* stackPointer = otherThreadStackPointer(regs);
void* stackBase = otherThreadStackBase(regs, thread);
- markStackObjectsConservatively(stack, stackPointer, stackBase);
+ markStackObjectsConservatively(stackPointer, stackBase);
resumeThread(thread->platformThread);
}
#endif
-void Collector::markStackObjectsConservatively(MarkStack& stack)
+void Collector::markStackObjectsConservatively()
{
- markCurrentThreadConservatively(stack);
+ markCurrentThreadConservatively();
#if USE(MULTIPLE_THREADS)
for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
if (!pthread_equal(thread->posixThread, pthread_self())) {
- markOtherThreadConservatively(stack, thread);
+ markOtherThreadConservatively(thread);
}
}
#endif
++mainThreadOnlyObjectCount;
}
-void Collector::markProtectedObjects(MarkStack& stack)
+void Collector::markProtectedObjects()
{
ProtectCountSet& protectedValues = KJS::protectedValues();
ProtectCountSet::iterator end = protectedValues.end();
for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) {
- stack.push(it->first);
- drainMarkStack(stack);
+ JSCell *val = it->first;
+ if (!val->marked())
+ val->mark();
}
}
-void Collector::markMainThreadOnlyObjects(MarkStack& stack)
+void Collector::markMainThreadOnlyObjects()
{
#if USE(MULTIPLE_THREADS)
ASSERT(!onMainThread());
if (curBlock->collectOnMainThreadOnly.get(i)) {
if (!curBlock->marked.get(i)) {
JSCell* imp = reinterpret_cast<JSCell*>(cell);
- stack.push(imp);
- drainMarkStack(stack);
+ imp->mark();
}
if (++count == mainThreadOnlyObjectCount)
return;
// MARK: first mark all referenced objects recursively starting out from the set of root objects
- size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
-
- MarkStack stack;
- stack.reserveCapacity(primaryHeap.numLiveObjects);
-
#ifndef NDEBUG
// Forbid malloc during the mark phase. Marking a thread suspends it, so
- // a malloc inside markChildren() would risk a deadlock with a thread that had been
+ // a malloc inside mark() would risk a deadlock with a thread that had been
// suspended while holding the malloc lock.
fastMallocForbid();
#endif
if (Interpreter::s_hook) {
Interpreter* scr = Interpreter::s_hook;
do {
- scr->markRoots(stack);
- drainMarkStack(stack);
+ scr->mark();
scr = scr->next;
} while (scr != Interpreter::s_hook);
}
- markStackObjectsConservatively(stack);
- markProtectedObjects(stack);
- List::markProtectedLists(stack);
- drainMarkStack(stack);
+ markStackObjectsConservatively();
+ markProtectedObjects();
+ List::markProtectedLists();
#if USE(MULTIPLE_THREADS)
if (!currentThreadIsMainThread)
- markMainThreadOnlyObjects(stack);
+ markMainThreadOnlyObjects();
#endif
#ifndef NDEBUG
fastMallocAllow();
#endif
+ size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
size_t numLiveObjects = sweep<PrimaryHeap>(currentThreadIsMainThread);
numLiveObjects += sweep<NumberHeap>(currentThreadIsMainThread);
namespace KJS {
- class CollectorBlock;
class JSCell;
class JSValue;
- class MarkStack;
+ class CollectorBlock;
class Collector {
public:
static bool isCellMarked(const JSCell*);
static void markCell(JSCell*);
- static bool cellMayHaveRefs(const JSCell*);
enum HeapType { PrimaryHeap, NumberHeap };
Collector();
static void recordExtraCost(size_t);
- static void markProtectedObjects(MarkStack&);
- static void markMainThreadOnlyObjects(MarkStack&);
- static void markCurrentThreadConservatively(MarkStack&);
- static void markOtherThreadConservatively(MarkStack&, Thread*);
- static void markStackObjectsConservatively(MarkStack&);
- static void markStackObjectsConservatively(MarkStack&, void* start, void* end);
+ static void markProtectedObjects();
+ static void markMainThreadOnlyObjects();
+ static void markCurrentThreadConservatively();
+ static void markOtherThreadConservatively(Thread*);
+ static void markStackObjectsConservatively();
+ static void markStackObjectsConservatively(void* start, void* end);
static size_t mainThreadOnlyObjectCount;
static bool memoryFull;
const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
const size_t CELL_MASK = CELL_SIZE - 1;
const size_t CELL_ALIGN_MASK = ~CELL_MASK;
- const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
CollectorCell cells[CELLS_PER_BLOCK];
uint32_t usedCells;
CollectorCell* freeList;
- uint32_t mayHaveRefs;
CollectorBitmap marked;
CollectorBitmap collectOnMainThreadOnly;
};
SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
uint32_t usedCells;
SmallCollectorCell* freeList;
- uint32_t mayHaveRefs;
CollectorBitmap marked;
CollectorBitmap collectOnMainThreadOnly;
};
cellBlock(cell)->marked.set(cellOffset(cell));
}
- inline bool Collector::cellMayHaveRefs(const JSCell* cell)
- {
- return cellBlock(cell)->mayHaveRefs;
- }
-
inline void Collector::reportExtraMemoryCost(size_t cost)
{
if (cost > minExtraCostSize)
return construct(exec, args);
}
+void NativeErrorImp::mark()
+{
+ JSObject::mark();
+ if (proto && !proto->marked())
+ proto->mark();
+}
virtual JSObject *construct(ExecState *exec, const List &args);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
+ virtual void mark();
+
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
private:
{
}
-void FunctionImp::markChildren(MarkStack& stack)
+void FunctionImp::mark()
{
- InternalFunctionImp::markChildren(stack);
- _scope.markChildren(stack);
+ InternalFunctionImp::mark();
+ _scope.mark();
}
JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
// ECMA 10.1.8
Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act)
- : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype())
- , _activationObject(act)
- , indexToNameMap(func, args)
+: JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()),
+_activationObject(act),
+indexToNameMap(func, args)
{
putDirect(exec->propertyNames().callee, func, DontEnum);
putDirect(exec->propertyNames().length, args.size(), DontEnum);
}
}
-void Arguments::markChildren(MarkStack& stack)
+void Arguments::mark()
{
- JSObject::markChildren(stack);
- stack.push(_activationObject);
+ JSObject::mark();
+ if (_activationObject && !_activationObject->marked())
+ _activationObject->mark();
}
JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
_prop.put(propertyName, value, attr, (attr == None || attr == DontDelete));
}
-void ActivationImp::markChildren(MarkStack& stack)
+void ActivationImp::mark()
{
- JSObject::markChildren(stack);
+ JSObject::mark();
size_t size = d->localStorage.size();
- for (size_t i = 0; i < size; ++i)
- stack.push(d->localStorage[i].value);
+ for (size_t i = 0; i < size; ++i) {
+ JSValue* value = d->localStorage[i].value;
+ if (!value->marked())
+ value->mark();
+ }
- stack.push(d->function);
- if (d->argumentsObject)
- stack.push(d->argumentsObject);
+ ASSERT(d->function);
+ if (!d->function->marked())
+ d->function->mark();
+
+ if (d->argumentsObject && !d->argumentsObject->marked())
+ d->argumentsObject->mark();
}
void ActivationImp::createArgumentsObject(ExecState* exec)
void setScope(const ScopeChain& s) { _scope = s; }
const ScopeChain& scope() const { return _scope; }
- virtual void markChildren(MarkStack&);
+ virtual void mark();
private:
ScopeChain _scope;
class Arguments : public JSObject {
public:
Arguments(ExecState*, FunctionImp* func, const List& args, ActivationImp* act);
- virtual void markChildren(MarkStack&);
+ virtual void mark();
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, int attr = None);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
- virtual void markChildren(MarkStack&);
+ virtual void mark();
bool isActivation() { return true; }
}
// --------------------------- GetterSetterImp ---------------------------------
-void GetterSetterImp::markChildren(MarkStack& stack)
+void GetterSetterImp::mark()
{
- if (getter)
- stack.push(getter);
- if (setter)
- stack.push(setter);
+ JSCell::mark();
+
+ if (getter && !getter->marked())
+ getter->mark();
+ if (setter && !setter->marked())
+ setter->mark();
}
JSValue* GetterSetterImp::toPrimitive(ExecState*, JSType) const
return m_UriErrorPrototype;
}
-void Interpreter::markRoots(MarkStack& stack)
+void Interpreter::mark()
{
if (m_currentExec)
- m_currentExec->markChildren(stack);
-
- if (m_globalExec.exception())
- stack.push(m_globalExec.exception());
-
- if (m_globalObject)
- stack.push(m_globalObject);
-
- if (m_Object)
- stack.push(m_Object);
- if (m_Function)
- stack.push(m_Function);
- if (m_Array)
- stack.push(m_Array);
- if (m_Boolean)
- stack.push(m_Boolean);
- if (m_String)
- stack.push(m_String);
- if (m_Number)
- stack.push(m_Number);
- if (m_Date)
- stack.push(m_Date);
- if (m_RegExp)
- stack.push(m_RegExp);
- if (m_Error)
- stack.push(m_Error);
-
- if (m_ObjectPrototype)
- stack.push(m_ObjectPrototype);
- if (m_FunctionPrototype)
- stack.push(m_FunctionPrototype);
- if (m_ArrayPrototype)
- stack.push(m_ArrayPrototype);
- if (m_BooleanPrototype)
- stack.push(m_BooleanPrototype);
- if (m_StringPrototype)
- stack.push(m_StringPrototype);
- if (m_NumberPrototype)
- stack.push(m_NumberPrototype);
- if (m_DatePrototype)
- stack.push(m_DatePrototype);
- if (m_RegExpPrototype)
- stack.push(m_RegExpPrototype);
- if (m_ErrorPrototype)
- stack.push(m_ErrorPrototype);
-
- if (m_EvalError)
- stack.push(m_EvalError);
- if (m_RangeError)
- stack.push(m_RangeError);
- if (m_ReferenceError)
- stack.push(m_ReferenceError);
- if (m_SyntaxError)
- stack.push(m_SyntaxError);
- if (m_TypeError)
- stack.push(m_TypeError);
- if (m_UriError)
- stack.push(m_UriError);
-
- if (m_EvalErrorPrototype)
- stack.push(m_EvalErrorPrototype);
- if (m_RangeErrorPrototype)
- stack.push(m_RangeErrorPrototype);
- if (m_ReferenceErrorPrototype)
- stack.push(m_ReferenceErrorPrototype);
- if (m_SyntaxErrorPrototype)
- stack.push(m_SyntaxErrorPrototype);
- if (m_TypeErrorPrototype)
- stack.push(m_TypeErrorPrototype);
- if (m_UriErrorPrototype)
- stack.push(m_UriErrorPrototype);
+ m_currentExec->mark();
+
+ if (m_globalExec.exception() && !m_globalExec.exception()->marked())
+ m_globalExec.exception()->mark();
+
+ if (m_globalObject && !m_globalObject->marked())
+ m_globalObject->mark();
+
+ if (m_Object && !m_Object->marked())
+ m_Object->mark();
+ if (m_Function && !m_Function->marked())
+ m_Function->mark();
+ if (m_Array && !m_Array->marked())
+ m_Array->mark();
+ if (m_Boolean && !m_Boolean->marked())
+ m_Boolean->mark();
+ if (m_String && !m_String->marked())
+ m_String->mark();
+ if (m_Number && !m_Number->marked())
+ m_Number->mark();
+ if (m_Date && !m_Date->marked())
+ m_Date->mark();
+ if (m_RegExp && !m_RegExp->marked())
+ m_RegExp->mark();
+ if (m_Error && !m_Error->marked())
+ m_Error->mark();
+
+ if (m_ObjectPrototype && !m_ObjectPrototype->marked())
+ m_ObjectPrototype->mark();
+ if (m_FunctionPrototype && !m_FunctionPrototype->marked())
+ m_FunctionPrototype->mark();
+ if (m_ArrayPrototype && !m_ArrayPrototype->marked())
+ m_ArrayPrototype->mark();
+ if (m_BooleanPrototype && !m_BooleanPrototype->marked())
+ m_BooleanPrototype->mark();
+ if (m_StringPrototype && !m_StringPrototype->marked())
+ m_StringPrototype->mark();
+ if (m_NumberPrototype && !m_NumberPrototype->marked())
+ m_NumberPrototype->mark();
+ if (m_DatePrototype && !m_DatePrototype->marked())
+ m_DatePrototype->mark();
+ if (m_RegExpPrototype && !m_RegExpPrototype->marked())
+ m_RegExpPrototype->mark();
+ if (m_ErrorPrototype && !m_ErrorPrototype->marked())
+ m_ErrorPrototype->mark();
+
+ if (m_EvalError && !m_EvalError->marked())
+ m_EvalError->mark();
+ if (m_RangeError && !m_RangeError->marked())
+ m_RangeError->mark();
+ if (m_ReferenceError && !m_ReferenceError->marked())
+ m_ReferenceError->mark();
+ if (m_SyntaxError && !m_SyntaxError->marked())
+ m_SyntaxError->mark();
+ if (m_TypeError && !m_TypeError->marked())
+ m_TypeError->mark();
+ if (m_UriError && !m_UriError->marked())
+ m_UriError->mark();
+
+ if (m_EvalErrorPrototype && !m_EvalErrorPrototype->marked())
+ m_EvalErrorPrototype->mark();
+ if (m_RangeErrorPrototype && !m_RangeErrorPrototype->marked())
+ m_RangeErrorPrototype->mark();
+ if (m_ReferenceErrorPrototype && !m_ReferenceErrorPrototype->marked())
+ m_ReferenceErrorPrototype->mark();
+ if (m_SyntaxErrorPrototype && !m_SyntaxErrorPrototype->marked())
+ m_SyntaxErrorPrototype->mark();
+ if (m_TypeErrorPrototype && !m_TypeErrorPrototype->marked())
+ m_TypeErrorPrototype->mark();
+ if (m_UriErrorPrototype && !m_UriErrorPrototype->marked())
+ m_UriErrorPrototype->mark();
}
static bool printExceptions = false;
* Called during the mark phase of the garbage collector. Subclasses
* implementing custom mark methods must make sure to chain to this one.
*/
- virtual void markRoots(MarkStack&);
+ virtual void mark();
static bool shouldPrintExceptions();
static void setShouldPrintExceptions(bool);
return staticMarkSet;
}
-void List::markProtectedListsSlowCase(MarkStack& stack)
+void List::markProtectedListsSlowCase()
{
ListSet::iterator end = markSet().end();
for (ListSet::iterator it = markSet().begin(); it != end; ++it) {
List* list = *it;
iterator end2 = list->end();
- for (iterator it2 = list->begin(); it2 != end2; ++it2)
- stack.push(*it2);
+ for (iterator it2 = list->begin(); it2 != end2; ++it2) {
+ JSValue* v = *it2;
+ if (!v->marked())
+ v->mark();
+ }
}
}
const_iterator begin() const { return m_vector.begin(); }
const_iterator end() const { return m_vector.end(); }
- static void markProtectedLists(MarkStack& stack)
+ static void markProtectedLists()
{
if (!markSet().size())
return;
- markProtectedListsSlowCase(stack);
+ markProtectedListsSlowCase();
}
static const List& empty(); // Fast path for an empty list.
private:
static ListSet& markSet();
- static void markProtectedListsSlowCase(MarkStack&);
+ static void markProtectedListsSlowCase();
void expandAndAppend(JSValue*);
// ------------------------------ JSObject ------------------------------------
-void JSObject::markChildren(MarkStack& stack)
+void JSObject::mark()
{
+ JSCell::mark();
+
#if JAVASCRIPT_MARK_TRACING
static int markStackDepth = 0;
markStackDepth++;
printf("%s (%p)\n", className().UTF8String().c_str(), this);
#endif
- stack.push(_proto);
- _prop.markChildren(stack);
+ JSValue *proto = _proto;
+ if (!proto->marked())
+ proto->mark();
+
+ _prop.mark();
#if JAVASCRIPT_MARK_TRACING
markStackDepth--;
#include "JSType.h"
#include "CommonIdentifiers.h"
-#include "MarkStack.h"
#include "interpreter.h"
#include "property_map.h"
#include "property_slot.h"
virtual UString toString(ExecState *exec) const;
virtual JSObject *toObject(ExecState *exec) const;
- virtual void markChildren(MarkStack&);
+ virtual void mark();
JSObject *getGetter() { return getter; }
void setGetter(JSObject *g) { getter = g; }
*/
JSObject();
- virtual void markChildren(MarkStack&);
+ virtual void mark();
virtual JSType type() const;
/**
// FIXME: Put this function in a separate file named something like scope_chain_mark.h -- can't put it in scope_chain.h since it depends on JSObject.
-inline void ScopeChain::markChildren(MarkStack& stack)
+inline void ScopeChain::mark()
{
- for (ScopeChainNode* n = _node; n; n = n->next) {
- JSObject* o = n->object;
- stack.push(o);
+ for (ScopeChainNode *n = _node; n; n = n->next) {
+ JSObject *o = n->object;
+ if (!o->marked())
+ o->mark();
}
}
checkConsistency();
}
-void PropertyMap::markChildren(MarkStack& stack) const
+void PropertyMap::mark() const
{
if (!m_usingTable) {
#if USE_SINGLE_ENTRY
- if (m_singleEntryKey)
- stack.push(m_u.singleEntryValue);
+ if (m_singleEntryKey) {
+ JSValue* v = m_u.singleEntryValue;
+ if (!v->marked())
+ v->mark();
+ }
#endif
return;
}
unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; i++)
- stack.push(m_u.table->entries()[i].value);
+ for (unsigned i = 1; i <= entryCount; i++) {
+ JSValue* v = m_u.table->entries()[i].value;
+ if (!v->marked())
+ v->mark();
+ }
}
static int comparePropertyMapEntryIndices(const void* a, const void* b)
class JSObject;
class JSValue;
- class MarkStack;
class PropertyNameArray;
struct PropertyMapEntry;
JSValue* get(const Identifier&, unsigned& attributes) const;
JSValue** getLocation(const Identifier& name);
- void markChildren(MarkStack&) const;
+ void mark() const;
void getEnumerablePropertyNames(PropertyNameArray&) const;
void save(SavedProperties&) const;
void push(const ScopeChain &);
void pop();
- void markChildren(MarkStack&);
+ void mark();
#ifndef NDEBUG
void print();
return JSObject::getPropertyNames(exec, propertyNames);
}
-void StringInstance::markChildren(MarkStack& stack)
-{
- JSObject::markChildren(stack);
- stack.pushAtom(internalValue());
-}
-
// ------------------------------ StringPrototype ---------------------------
const ClassInfo StringPrototype::info = { "String", &StringInstance::info, &stringTable };
/* Source for string_object.lut.h
static const ClassInfo info;
StringImp* internalValue() const { return static_cast<StringImp*>(JSWrapperObject::internalValue());}
- virtual void markChildren(MarkStack& stack);
private:
bool inlineGetOwnPropertySlot(ExecState*, unsigned, PropertySlot&);
class ExecState;
class JSObject;
class JSCell;
-class MarkStack;
struct ClassInfo;
class JSValue : Noncopyable {
friend class JSCell; // so it can derive from this class
friend class Collector; // so it can call asCell()
- friend class MarkStack; // so it can call asCell()
private:
JSValue();
float toFloat(ExecState*) const;
// Garbage collection.
- void markChildren(MarkStack&);
+ void mark();
bool marked() const;
static int32_t toInt32SlowCase(double, bool& ok);
// Garbage collection.
void *operator new(size_t);
- virtual void markChildren(MarkStack&);
+ virtual void mark();
bool marked() const;
};
return Collector::isCellMarked(this);
}
-inline void JSCell::markChildren(MarkStack&)
+inline void JSCell::mark()
{
+ return Collector::markCell(this);
}
ALWAYS_INLINE JSCell* JSValue::asCell()
return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v);
}
-inline void JSValue::markChildren(MarkStack& stack)
+inline void JSValue::mark()
{
- ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling markChildren()
- asCell()->markChildren(stack);
+ ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
+ asCell()->mark();
}
inline bool JSValue::marked() const
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Reviewed by Darin and Geoff.
-
- Fixups for JavaScriptCore mark stack.
-
- * JSObject.cpp:
- (JSUserObject::Mark):
- * JSObject.h:
- * JSValueWrapper.cpp:
- (JSValueWrapper::JSObjectMark):
- * JSValueWrapper.h:
- * UserObjectImp.cpp:
- * UserObjectImp.h:
-
2007-11-27 Anders Carlsson <andersca@apple.com>
Build fix.
return result;
}
-void JSUserObject::Mark(KJS::MarkStack& stack)
+void JSUserObject::Mark()
{
if (fMarkProc)
{
- fMarkProc(stack, fData);
+ fMarkProc(fData);
}
}
#include "JSBase.h"
#include "JSUtils.h"
-typedef void (*JSObjectMarkProcPtr)(MarkStack&, void *data);
+typedef void (*JSObjectMarkProcPtr)(void *data);
JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int dataType);
class JSUserObject : public JSBase {
CFTypeRef CopyCFValue() const;
virtual UInt8 Equal(JSBase* other);
void *GetData();
- void Mark(KJS::MarkStack&);
+ void Mark();
int DataType() const { return fDataType; }
private:
return result;
}
-void JSValueWrapper::JSObjectMark(MarkStack& stack, void *data)
+void JSValueWrapper::JSObjectMark(void *data)
{
JSValueWrapper* ptr = (JSValueWrapper*)data;
if (ptr)
{
- ptr->fValue->markChildren(stack);
+ ptr->fValue->mark();
}
}
static void JSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue);
static JSObjectRef JSObjectCallFunction(void *data, JSObjectRef thisObj, CFArrayRef args);
static CFTypeRef JSObjectCopyCFValue(void *data);
- static void JSObjectMark(KJS::MarkStack&, void *data);
+ static void JSObjectMark(void *data);
};
#endif
return result;
}
-void UserObjectImp::markChildren(MarkStack& stack)
+void UserObjectImp::mark()
{
- JSObject::markChildren(stack);
+ JSObject::mark();
if (fJSUserObject)
- fJSUserObject->Mark(stack);
+ fJSUserObject->Mark();
}
virtual double toNumber(ExecState *exec) const;
virtual UString toString(ExecState *exec) const;
- virtual void markChildren(MarkStack& stack);
+ virtual void mark();
JSUserObject *GetJSUserObject() const;
private:
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- add files missing from previous commit.
-
- * fast/js/gc-breadth-2-expected.txt: Added.
- * fast/js/gc-breadth-2.html: Added.
- * fast/js/gc-breadth-expected.txt: Added.
- * fast/js/gc-breadth.html: Added.
- * fast/js/gc-depth-expected.txt: Added.
- * fast/js/gc-depth.html: Added.
- * fast/js/resources/gc-breadth-2.js: Added.
- * fast/js/resources/gc-breadth.js: Added.
- * fast/js/resources/gc-depth.js: Added.
-
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Not reviewed.
-
- - Test cases for "Stack overflow crash in JavaScript garbage collector mark pass"
- http://bugs.webkit.org/show_bug.cgi?id=12216
-
- I have fixed this with the mark stack work.
-
- * fast/js/gc-breadth-2-expected.txt: Added.
- * fast/js/gc-breadth-2.html: Added.
- * fast/js/gc-breadth-expected.txt: Added.
- * fast/js/gc-breadth.html: Added.
- * fast/js/gc-depth-expected.txt: Added.
- * fast/js/gc-depth.html: Added.
- * fast/js/resources/gc-breadth-2.js: Added.
- * fast/js/resources/gc-breadth.js: Added.
- * fast/js/resources/gc-depth.js: Added.
-
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Not reviewed.
-
- - Test cases for "Stack overflow crash in JavaScript garbage collector mark pass"
- http://bugs.webkit.org/show_bug.cgi?id=12216
-
- I have fixed this with the mark stack work.
-
- * fast/js/gc-breadth-2-expected.txt: Added.
- * fast/js/gc-breadth-2.html: Added.
- * fast/js/gc-breadth-expected.txt: Added.
- * fast/js/gc-breadth.html: Added.
- * fast/js/gc-depth-expected.txt: Added.
- * fast/js/gc-depth.html: Added.
- * fast/js/resources/gc-breadth-2.js: Added.
- * fast/js/resources/gc-breadth.js: Added.
- * fast/js/resources/gc-depth.js: Added.
-
2007-11-27 Beth Dakin <bdakin@apple.com>
Reviewed by Oliver.
+++ /dev/null
-This test makes sure that wide object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-This test makes sure that wide object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-breadth-2.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-breadth-2.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
+++ /dev/null
-This test makes sure that wide object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-This test makes sure that wide object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-breadth.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-breadth.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
+++ /dev/null
-This test makes sure that deep object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-This test makes sure that deep object structures don't lead to GC crashes.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-depth.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<link rel="stylesheet" href="resources/js-test-style.css">
-<script src="resources/js-test-pre.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="resources/gc-depth.js"></script>
-<script src="resources/js-test-post.js"></script>
-</body>
-</html>
+++ /dev/null
-description("This test makes sure that wide object structures don't lead to GC crashes.")
-
-var a = {};
-for (var i = 0; i < 200000; i++) {
- a[i] = {};
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
-description("This test makes sure that wide object structures don't lead to GC crashes.")
-
-var a = {};
-for (var i = 0; i < 200000; i++) {
- a[i] = {};
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
+++ /dev/null
-description("This test makes sure that wide object structures don't lead to GC crashes.")
-
-var a = [];
-for (var i = 0; i < 200000; i++) {
- a[i] = [];
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
-description("This test makes sure that wide object structures don't lead to GC crashes.")
-
-var a = [];
-for (var i = 0; i < 200000; i++) {
- a[i] = [];
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
+++ /dev/null
-description("This test makes sure that deep object structures don't lead to GC crashes.")
-
-var a = [];
-for (var i = 0; i < 200000; i++) {
- a = [a];
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
-description("This test makes sure that deep object structures don't lead to GC crashes.")
-
-var a = [];
-for (var i = 0; i < 200000; i++) {
- a = [a];
-}
-
-var b = "";
-for (var i = 0; i < 80000; i++) {
- b += "b";
-}
-
-var successfullyParsed = true;
* platform/graphics/cairo/ImageSourceCairo.cpp:
(WebCore::ImageSource::frameHasAlphaAtIndex):
-2007-11-28 Maciej Stachowiak <mjs@apple.com>
-
- Reviewed by Darin and Geoff.
-
- Implement mark stack. This version is not suitable for prime time because it makes a
- huge allocation on every collect, and potentially makes marking of detached subtrees
- slow. But it is a .2% - .4% speedup even without much tweaking.
-
- I replaced mark() methods with markChildren() as usual. One
- optimization that is lost is avoiding walking detached DOM
- subtrees more than once to mark them; since marking is not
- recursive there's no obvious way to bracket operation on the tree
- any more.
-
- * bindings/js/JSDocumentCustom.cpp:
- (WebCore::JSDocument::markChildren):
- * bindings/js/JSNodeCustom.cpp:
- (WebCore::JSNode::markChildren):
- * bindings/js/JSNodeFilterCondition.cpp:
- * bindings/js/JSNodeFilterCondition.h:
- * bindings/js/JSNodeFilterCustom.cpp:
- (WebCore::JSNodeFilter::markChildren):
- * bindings/js/JSNodeIteratorCustom.cpp:
- (WebCore::JSNodeIterator::markChildren):
- * bindings/js/JSTreeWalkerCustom.cpp:
- (WebCore::JSTreeWalker::markChildren):
- * bindings/js/JSXMLHttpRequest.cpp:
- (KJS::JSXMLHttpRequest::markChildren):
- * bindings/js/JSXMLHttpRequest.h:
- * bindings/js/kjs_binding.cpp:
- (KJS::ScriptInterpreter::markDOMNodesForDocument):
- * bindings/js/kjs_binding.h:
- * bindings/js/kjs_events.cpp:
- (WebCore::JSUnprotectedEventListener::markChildren):
- * bindings/js/kjs_events.h:
- * bindings/js/kjs_window.cpp:
- (KJS::Window::markChildren):
- * bindings/js/kjs_window.h:
- * bindings/scripts/CodeGeneratorJS.pm:
- * dom/Node.cpp:
- (WebCore::Node::Node):
- * dom/Node.h:
- * dom/NodeFilter.h:
- * dom/NodeFilterCondition.h:
-
2007-11-27 Alp Toker <alp@atoker.com>
Reviewed by Mark Rowe.
using namespace KJS;
-void JSDocument::markChildren(MarkStack& stack)
+void JSDocument::mark()
{
- DOMObject::markChildren(stack);
- ScriptInterpreter::markDOMNodesForDocument(stack, static_cast<Document*>(impl()));
+ DOMObject::mark();
+ ScriptInterpreter::markDOMNodesForDocument(static_cast<Document*>(impl()));
}
JSValue* JSDocument::location(ExecState* exec) const
return KJS::jsNull();
}
-void JSNode::markChildren(KJS::MarkStack& stack)
+void JSNode::mark()
{
ASSERT(!marked());
// Nodes in the document are kept alive by ScriptInterpreter::mark,
// so we have no special responsibilities and can just call the base class here.
if (node->inDocument()) {
- DOMObject::markChildren(stack);
+ DOMObject::mark();
return;
}
for (Node* current = m_impl.get(); current; current = current->parentNode())
root = current;
- // Mark the whole tree
- for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode())
- if (JSNode* wrapper = KJS::ScriptInterpreter::getDOMNodeForDocument(m_impl->document(), nodeToMark))
- stack.push(wrapper);
+ // If we're already marking this tree, then we can simply mark this wrapper
+ // by calling the base class; our caller is iterating the tree.
+ if (root->m_inSubtreeMark) {
+ DOMObject::mark();
+ return;
+ }
- DOMObject::markChildren(stack);
+ // Mark the whole tree; use the global set of roots to avoid reentering.
+ root->m_inSubtreeMark = true;
+ for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) {
+ JSNode* wrapper = KJS::ScriptInterpreter::getDOMNodeForDocument(m_impl->document(), nodeToMark);
+ if (wrapper) {
+ if (!wrapper->marked())
+ wrapper->mark();
+ } else if (nodeToMark == node) {
+ // This is the case where the map from the document to wrappers has
+ // been cleared out, but a wrapper is being marked. For now, we'll
+ // let the rest of the tree of wrappers get collected, because we have
+ // no good way of finding them. Later we should test behavior of other
+ // browsers and see if we need to preserve other wrappers in this case.
+ if (!marked())
+ mark();
+ }
+ }
+ root->m_inSubtreeMark = false;
// Double check that we actually ended up marked. This assert caught problems in the past.
ASSERT(marked());
{
}
-void JSNodeFilterCondition::markChildren(KJS::MarkStack& stack)
+void JSNodeFilterCondition::mark()
{
- stack.push(m_filter);
+ m_filter->mark();
}
short JSNodeFilterCondition::acceptNode(Node* filterNode) const
public:
JSNodeFilterCondition(KJS::JSObject* filter);
virtual short acceptNode(Node*) const;
- virtual void markChildren(KJS::MarkStack&);
+ virtual void mark();
protected:
KJS::JSObject* m_filter;
namespace WebCore {
- void JSNodeFilter::markChildren(KJS::MarkStack& stack)
+void JSNodeFilter::mark()
{
- impl()->markChildren(stack);
- DOMObject::markChildren(stack);
+ impl()->mark();
+ DOMObject::mark();
}
NodeFilter* toNodeFilter(KJS::JSValue* val)
namespace WebCore {
-void JSNodeIterator::markChildren(KJS::MarkStack& stack)
+void JSNodeIterator::mark()
{
if (NodeFilter* filter = m_impl->filter())
- filter->markChildren(stack);
+ filter->mark();
- DOMObject::markChildren(stack);
+ DOMObject::mark();
}
}
namespace WebCore {
-void JSTreeWalker::markChildren(KJS::MarkStack& stack)
+void JSTreeWalker::mark()
{
if (NodeFilter* filter = m_impl->filter())
- filter->markChildren(stack);
+ filter->mark();
- DOMObject::markChildren(stack);
+ DOMObject::mark();
}
}
}
}
-void JSXMLHttpRequest::markChildren(KJS::MarkStack& stack)
+void JSXMLHttpRequest::mark()
{
- DOMObject::markChildren(stack);
+ DOMObject::mark();
JSUnprotectedEventListener* onReadyStateChangeListener = static_cast<JSUnprotectedEventListener*>(m_impl->onReadyStateChangeListener());
JSUnprotectedEventListener* onLoadListener = static_cast<JSUnprotectedEventListener*>(m_impl->onLoadListener());
if (onReadyStateChangeListener)
- onReadyStateChangeListener->markChildren(stack);
+ onReadyStateChangeListener->mark();
if (onLoadListener)
- onLoadListener->markChildren(stack);
+ onLoadListener->mark();
typedef XMLHttpRequest::EventListenersMap EventListenersMap;
typedef XMLHttpRequest::ListenerVector ListenerVector;
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(vecIter->get());
- listener->markChildren(stack);
+ listener->mark();
}
}
}
virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, int attr = None);
void putValueProperty(ExecState*, int token, JSValue* value, int /*attr*/);
virtual bool toBoolean(ExecState*) const { return true; }
- virtual void markChildren(MarkStack&);
+ virtual void mark();
WebCore::XMLHttpRequest* impl() const { return m_impl.get(); }
delete map;
}
-void ScriptInterpreter::markDOMNodesForDocument(MarkStack& stack, Document* doc)
+void ScriptInterpreter::markDOMNodesForDocument(Document* doc)
{
NodePerDocMap::iterator dictIt = domNodesPerDocument().find(doc);
if (dictIt != domNodesPerDocument().end()) {
// otherwise reachable from JS.
// However, image elements that aren't in the document are also
// marked, if they are not done loading yet.
- if (node->inDocument() || (node->hasTagName(imgTag) &&
- !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()))
- stack.push(jsNode);
+ if (!jsNode->marked() && (node->inDocument() || (node->hasTagName(imgTag) &&
+ !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())))
+ jsNode->mark();
}
}
}
static void forgetDOMNodeForDocument(WebCore::Document*, WebCore::Node*);
static void forgetAllDOMNodesForDocument(WebCore::Document*);
static void updateDOMNodeDocument(WebCore::Node*, WebCore::Document* oldDoc, WebCore::Document* newDoc);
- static void markDOMNodesForDocument(MarkStack&, WebCore::Document*);
+ static void markDOMNodesForDocument(WebCore::Document*);
WebCore::Frame* frame() const { return m_frame; }
m_win = 0;
}
-void JSUnprotectedEventListener::markChildren(KJS::MarkStack& stack)
+void JSUnprotectedEventListener::mark()
{
- if (m_listener)
- stack.push(m_listener);
+ if (m_listener && !m_listener->marked())
+ m_listener->mark();
}
#ifndef NDEBUG
virtual KJS::JSObject* listenerObj() const;
virtual KJS::Window* windowObj() const;
void clearWindowObj();
- virtual void markChildren(KJS::MarkStack&);
+ virtual void mark();
private:
KJS::JSObject* m_listener;
KJS::Window* m_win;
}
// reference our special objects during garbage collection
-void Window::markChildren(KJS::MarkStack& stack)
+void Window::mark()
{
- JSObject::markChildren(stack);
- if (d->loc)
- stack.push(d->loc);
+ JSObject::mark();
+ if (d->loc && !d->loc->marked())
+ d->loc->mark();
}
static bool allowPopUp(ExecState *exec, Window *window)
* was called from.
*/
static Window* retrieveActive(ExecState*);
- virtual void markChildren(MarkStack&);
+ virtual void mark();
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
JSValue *getValueProperty(ExecState *exec, int token) const;
virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None);
# Custom mark function
if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
- push(@headerContent, " virtual void markChildren(KJS::MarkStack&);\n\n");
+ push(@headerContent, " virtual void mark();\n\n");
}
# Custom pushEventHandlerScope function
m_hovered(false),
m_inActiveChain(false),
m_inDetach(false),
- m_dispatchingSimulatedEvent(false)
+ m_dispatchingSimulatedEvent(false),
+ m_inSubtreeMark(false)
{
#ifndef NDEBUG
if (shouldIgnoreLeaks)
bool m_inDetach : 1;
bool m_dispatchingSimulatedEvent : 1;
- // 1 bit left
+public:
+ bool m_inSubtreeMark : 1;
+ // 0 bits left
private:
Element* ancestorElement() const;
#include "NodeFilterCondition.h"
#include <wtf/RefPtr.h>
-namespace KJS {
- class MarkStack;
-}
-
namespace WebCore {
class NodeFilter : public RefCounted<NodeFilter> {
NodeFilter(NodeFilterCondition*);
short acceptNode(Node*) const;
- void markChildren(KJS::MarkStack& stack) { m_condition->markChildren(stack); };
+ void mark() { m_condition->mark(); };
private:
RefPtr<NodeFilterCondition> m_condition;
#include <wtf/RefCounted.h>
-namespace KJS {
- class MarkStack;
-}
-
namespace WebCore {
class Node;
public:
virtual ~NodeFilterCondition() { }
virtual short acceptNode(Node*) const;
- virtual void markChildren(KJS::MarkStack&) { }
+ virtual void mark() { }
};
} // namespace WebCore