Reviewed by Darin.
Enable full conservative GC mode in addition to test mode. When
conservative GC is enabled, we now get an 11% speed improvement on
the iBench. Also fix some spots I missed before.
Specific noteworth changes:
* kjs/collector.cpp:
(KJS::Collector::markStackObjectsConservatively): Check possible
cell pointers for 8-byte aligment and verify they are not 0.
* kjs/protected_values.cpp:
(KJS::ProtectedValues::increaseProtectCount): Move null-tolerance from here...
(KJS::ProtectedValues::decreaseProtectCount): ...and here...
* kjs/protect.h:
(KJS::gcProtectNullTolerant): ...to here...
(KJS::gcUnprotectNullTolerant): ...and here, because not all callers need the null
tolerance, and doing the check is expensive.
* kjs/protected_values.cpp:
(KJS::ProtectedValues::computeHash): Replace hash function with a much faster one
that is still very good.
* kjs/protect.h:
(KJS::gcProtect):
(KJS::gcUnprotect):
(KJS::ProtectedValue::ProtectedValue):
(KJS::ProtectedValue::~ProtectedValue):
(KJS::ProtectedValue::operator=):
(KJS::ProtectedObject::ProtectedObject):
(KJS::ProtectedObject::~ProtectedObject):
(KJS::ProtectedObject::operator=):
(KJS::ProtectedReference::ProtectedReference):
(KJS::ProtectedReference::~ProtectedReference):
(KJS::ProtectedReference::operator=):
* kjs/protected_values.cpp:
(KJS::ProtectedValues::getProtectCount):
(KJS::ProtectedValues::increaseProtectCount):
(KJS::ProtectedValues::decreaseProtectCount):
(KJS::ProtectedValues::computeHash):
* bindings/runtime_root.cpp:
(KJS::Bindings::addNativeReference):
(KJS::Bindings::removeNativeReference):
(RootObject::removeAllNativeReferences):
* bindings/runtime_root.h:
(KJS::Bindings::RootObject::~RootObject):
(KJS::Bindings::RootObject::setRootObjectImp):
* kjs/collector.cpp:
(KJS::Collector::allocate):
(KJS::Collector::collect):
* kjs/collector.h:
* kjs/internal.cpp:
(NumberImp::create):
(InterpreterImp::globalInit):
(InterpreterImp::globalClear):
(InterpreterImp::mark):
* kjs/list.cpp:
(KJS::List::derefValues):
(KJS::List::refValues):
(KJS::List::append):
* kjs/object.cpp:
(KJS::ObjectImp::setInternalValue):
(KJS::ObjectImp::putDirect):
* kjs/value.cpp:
(ValueImp::mark):
(ValueImp::marked):
* kjs/value.h:
(KJS::ValueImp::ValueImp):
(KJS::ValueImp::~ValueImp):
(KJS::ValueImp::):
(KJS::Value::Value):
(KJS::Value::~Value):
(KJS::Value::operator=):
WebCore:
Reviewed by Darin.
* khtml/ecma/kjs_events.cpp:
(JSLazyEventListener::parseCode): Make sure to protect the
permanent "event" string object.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@6549
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2004-04-25 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin.
+
+ Enable full conservative GC mode in addition to test mode. When
+ conservative GC is enabled, we now get an 11% speed improvement on
+ the iBench. Also fix some spots I missed before.
+
+ Specific noteworth changes:
+
+ * kjs/collector.cpp:
+ (KJS::Collector::markStackObjectsConservatively): Check possible
+ cell pointers for 8-byte aligment and verify they are not 0.
+
+ * kjs/protected_values.cpp:
+ (KJS::ProtectedValues::increaseProtectCount): Move null-tolerance from here...
+ (KJS::ProtectedValues::decreaseProtectCount): ...and here...
+ * kjs/protect.h:
+ (KJS::gcProtectNullTolerant): ...to here...
+ (KJS::gcUnprotectNullTolerant): ...and here, because not all callers need the null
+ tolerance, and doing the check is expensive.
+
+ * kjs/protected_values.cpp:
+ (KJS::ProtectedValues::computeHash): Replace hash function with a much faster one
+ that is still very good.
+
+ * kjs/protect.h:
+ (KJS::gcProtect):
+ (KJS::gcUnprotect):
+ (KJS::ProtectedValue::ProtectedValue):
+ (KJS::ProtectedValue::~ProtectedValue):
+ (KJS::ProtectedValue::operator=):
+ (KJS::ProtectedObject::ProtectedObject):
+ (KJS::ProtectedObject::~ProtectedObject):
+ (KJS::ProtectedObject::operator=):
+ (KJS::ProtectedReference::ProtectedReference):
+ (KJS::ProtectedReference::~ProtectedReference):
+ (KJS::ProtectedReference::operator=):
+ * kjs/protected_values.cpp:
+ (KJS::ProtectedValues::getProtectCount):
+ (KJS::ProtectedValues::increaseProtectCount):
+ (KJS::ProtectedValues::decreaseProtectCount):
+ (KJS::ProtectedValues::computeHash):
+ * bindings/runtime_root.cpp:
+ (KJS::Bindings::addNativeReference):
+ (KJS::Bindings::removeNativeReference):
+ (RootObject::removeAllNativeReferences):
+ * bindings/runtime_root.h:
+ (KJS::Bindings::RootObject::~RootObject):
+ (KJS::Bindings::RootObject::setRootObjectImp):
+ * kjs/collector.cpp:
+ (KJS::Collector::allocate):
+ (KJS::Collector::collect):
+ * kjs/collector.h:
+ * kjs/internal.cpp:
+ (NumberImp::create):
+ (InterpreterImp::globalInit):
+ (InterpreterImp::globalClear):
+ (InterpreterImp::mark):
+ * kjs/list.cpp:
+ (KJS::List::derefValues):
+ (KJS::List::refValues):
+ (KJS::List::append):
+ * kjs/object.cpp:
+ (KJS::ObjectImp::setInternalValue):
+ (KJS::ObjectImp::putDirect):
+ * kjs/value.cpp:
+ (ValueImp::mark):
+ (ValueImp::marked):
+ * kjs/value.h:
+ (KJS::ValueImp::ValueImp):
+ (KJS::ValueImp::~ValueImp):
+ (KJS::ValueImp::):
+ (KJS::Value::Value):
+ (KJS::Value::~Value):
+ (KJS::Value::operator=):
+
2004-04-30 Richard Williamson <rjw@apple.com>
Asking an NSInvocation for it's return value when return type
unsigned int numReferences = (unsigned int)CFDictionaryGetValue (referencesDictionary, imp);
if (numReferences == 0) {
- imp->ref();
+#if !USE_CONSERVATIVE_GC
+ imp->ref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcProtect(imp);
+#endif
CFDictionaryAddValue (referencesDictionary, imp, (const void *)1);
}
else {
void KJS::Bindings::removeNativeReference (ObjectImp *imp)
{
CFMutableDictionaryRef referencesDictionary = findReferenceDictionary (imp);
-
+
if (referencesDictionary) {
unsigned int numReferences = (unsigned int)CFDictionaryGetValue (referencesDictionary, imp);
if (numReferences == 1) {
- imp->deref();
+#if !USE_CONSERVATIVE_GC
+ imp->deref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcUnprotect(imp);
+#endif
CFDictionaryRemoveValue (referencesDictionary, imp);
}
else {
CFDictionaryGetKeysAndValues (referencesDictionary, (const void **)allImps, NULL);
for(i = 0; i < count; i++) {
ObjectImp *anImp = static_cast<ObjectImp*>(allImps[i]);
+#if !USE_CONSERVATIVE_GC
anImp->deref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcUnprotect(anImp);
+#endif
}
free ((void *)allImps);
CFDictionaryRemoveAllValues (referencesDictionary);
public:
RootObject (const void *nativeHandle) : _nativeHandle(nativeHandle), _imp(0), _interpreter(0) {}
~RootObject (){
+#if !USE_CONSERVATIVE_GC
_imp->deref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcUnprotect(_imp);
+#endif
}
void setRootObjectImp (KJS::ObjectImp *i) {
_imp = i;
+#if !USE_CONSERVATIVE_GC
_imp->ref();
+
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcProtect(_imp);
+#endif
}
KJS::ObjectImp *rootObjectImp() const { return _imp; }
heap.usedOversizeCells++;
heap.numLiveObjects++;
+#if !USE_CONSERVATIVE_GC
((ValueImp *)(newCell))->_flags = 0;
+#endif
return newCell;
}
targetBlock->usedCells++;
heap.numLiveObjects++;
+#if !USE_CONSERVATIVE_GC
((ValueImp *)(newCell))->_flags = 0;
+#endif
return (void *)(newCell);
}
-#if TEST_CONSERVATIVE_GC
-
-#define IS_POINTER_ALIGNED(p) (((int)(p) & (sizeof(char *) - 1)) == 0)
+#if TEST_CONSERVATIVE_GC || USE_CONSERVATIVE_GC
+
+// cells are 8-byte aligned
+#define IS_POINTER_ALIGNED(p) (((int)(p) & 7) == 0)
void Collector::markStackObjectsConservatively(void *start, void *end)
{
while (p != e) {
char *x = *p++;
- if (IS_POINTER_ALIGNED(x)) {
+ if (IS_POINTER_ALIGNED(x) && x) {
bool good = false;
for (int block = 0; block < heap.usedBlocks; block++) {
size_t offset = x - (char *)heap.blocks[block];
#if TEST_CONSERVATIVE_GC
// CONSERVATIVE MARK: mark the root set using conservative GC bit (will compare later)
ValueImp::useConservativeMark(true);
+#endif
+#if USE_CONSERVATIVE_GC || TEST_CONSERVATIVE_GC
if (InterpreterImp::s_hook) {
InterpreterImp *scr = InterpreterImp::s_hook;
do {
markStackObjectsConservatively();
markProtectedObjects();
+#endif
-
+#if TEST_CONSERVATIVE_GC
ValueImp::useConservativeMark(false);
#endif
+#if !USE_CONSERVATIVE_GC
// MARK: first mark all referenced objects recursively
// starting out from the set of root objects
if (InterpreterImp::s_hook) {
imp->mark();
}
}
+#endif
// SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
ValueImp *imp = (ValueImp *)(curBlock->cells + cell);
if (((CollectorCell *)imp)->u.freeCell.zeroIfFree != 0) {
- if (!imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) {
+#if USE_CONSERVATIVE_GC
+ if (!imp->_marked)
+#else
+ if (!imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED))
+#endif
+ {
//fprintf( stderr, "Collector::deleting ValueImp %p (%s)\n", (void*)imp, typeid(*imp).name());
// emulate destructing part of 'operator delete()'
imp->~ValueImp();
curBlock->freeList = (CollectorCell *)imp;
} else {
-#if TEST_CONSERVATIVE_GC
+#if USE_CONSERVATIVE_GC
+ imp->_marked = 0;
+#elif TEST_CONSERVATIVE_GC
imp->_flags &= ~(ValueImp::VI_MARKED | ValueImp::VI_CONSERVATIVE_MARKED);
#else
imp->_flags &= ~ValueImp::VI_MARKED;
while (cell < heap.usedOversizeCells) {
ValueImp *imp = (ValueImp *)heap.oversizeCells[cell];
+#if USE_CONSERVATIVE_GC
+ if (!imp->_marked) {
+#else
if (!imp->refcount &&
imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) {
-
+#endif
+
imp->~ValueImp();
#if DEBUG_COLLECTOR
heap.oversizeCells[cell]->u.freeCell.zeroIfFree = 0;
}
} else {
+#if USE_CONSERVATIVE_GC
+ imp->_marked = 0;
+#elif TEST_CONSERVATIVE_GC
+ imp->_flags &= ~(ValueImp::VI_MARKED | ValueImp::VI_CONSERVATIVE_MARKED);
+#else
imp->_flags &= ~ValueImp::VI_MARKED;
+#endif
cell++;
}
}
int Collector::numGCNotAllowedObjects()
{
int count = 0;
+#if !USE_CONSERVATIVE_GC
for (int block = 0; block < heap.usedBlocks; block++) {
CollectorBlock *curBlock = heap.blocks[block];
++count;
}
}
+#endif
return count;
}
int Collector::numReferencedObjects()
{
int count = 0;
+
+#if USE_CONSERVATIVE_GC
+ for (int i = 0; i < ProtectedValues::_tableSize; i++) {
+ ValueImp *val = ProtectedValues::_table[i].key;
+ if (val) {
+ ++count;
+ }
+ }
+
+#else
+
for (int block = 0; block < heap.usedBlocks; block++) {
CollectorBlock *curBlock = heap.blocks[block];
++count;
}
}
+#endif
return count;
}
const void *Collector::rootObjectClasses()
{
CFMutableSetRef classes = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
-
+
+#if USE_CONSERVATIVE_GC
+ for (int i = 0; i < ProtectedValues::_tableSize; i++) {
+ ValueImp *val = ProtectedValues::_table[i].key;
+ if (val) {
+ const char *mangled_name = typeid(*val).name();
+ int status;
+ char *demangled_name = __cxxabiv1::__cxa_demangle (mangled_name, NULL, NULL, &status);
+
+ CFStringRef className = CFStringCreateWithCString(NULL, demangled_name, kCFStringEncodingASCII);
+ free(demangled_name);
+ CFSetAddValue(classes, className);
+ CFRelease(className);
+ }
+ }
+#else
for (int block = 0; block < heap.usedBlocks; block++) {
CollectorBlock *curBlock = heap.blocks[block];
for (int cell = 0; cell < CELLS_PER_BLOCK; cell++) {
CFRelease(className);
}
}
+#endif
return classes;
}
#endif
private:
-#if TEST_CONSERVATIVE_GC
+#if TEST_CONSERVATIVE_GC | USE_CONSERVATIVE_GC
static void markProtectedObjects();
static void markStackObjectsConservatively();
static void markStackObjectsConservatively(void *start, void *end);
if (SimpleNumber::fits(i))
return SimpleNumber::make(i);
NumberImp *imp = new NumberImp(static_cast<double>(i));
+#if !USE_CONSERVATIVE_GC
imp->setGcAllowedFast();
+#endif
return imp;
}
if (isNaN(d))
return staticNaN;
NumberImp *imp = new NumberImp(d);
+#if !USE_CONSERVATIVE_GC
imp->setGcAllowedFast();
+#endif
return imp;
}
{
//fprintf( stderr, "InterpreterImp::globalInit()\n" );
UndefinedImp::staticUndefined = new UndefinedImp();
+#if !USE_CONSERVATIVE_GC
UndefinedImp::staticUndefined->ref();
+#endif
NullImp::staticNull = new NullImp();
+#if !USE_CONSERVATIVE_GC
NullImp::staticNull->ref();
+#endif
BooleanImp::staticTrue = new BooleanImp(true);
+#if !USE_CONSERVATIVE_GC
BooleanImp::staticTrue->ref();
+#endif
BooleanImp::staticFalse = new BooleanImp(false);
+#if !USE_CONSERVATIVE_GC
BooleanImp::staticFalse->ref();
+#endif
NumberImp::staticNaN = new NumberImp(NaN);
+#if !USE_CONSERVATIVE_GC
NumberImp::staticNaN->ref();
+#endif
}
void InterpreterImp::globalClear()
{
//fprintf( stderr, "InterpreterImp::globalClear()\n" );
+#if !USE_CONSERVATIVE_GC
UndefinedImp::staticUndefined->deref();
UndefinedImp::staticUndefined->setGcAllowed();
+#endif
UndefinedImp::staticUndefined = 0L;
+#if !USE_CONSERVATIVE_GC
NullImp::staticNull->deref();
NullImp::staticNull->setGcAllowed();
+#endif
NullImp::staticNull = 0L;
+#if !USE_CONSERVATIVE_GC
BooleanImp::staticTrue->deref();
BooleanImp::staticTrue->setGcAllowed();
+#endif
BooleanImp::staticTrue = 0L;
+#if !USE_CONSERVATIVE_GC
BooleanImp::staticFalse->deref();
BooleanImp::staticFalse->setGcAllowed();
+#endif
BooleanImp::staticFalse = 0L;
+#if !USE_CONSERVATIVE_GC
NumberImp::staticNaN->deref();
NumberImp::staticNaN->setGcAllowed();
+#endif
NumberImp::staticNaN = 0;
}
if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
BooleanImp::staticFalse->mark();
//fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
- if (global.imp())
- global.imp()->mark();
if (m_interpreter)
m_interpreter->mark();
if (_context)
int size = imp->size;
int inlineSize = MIN(size, inlineValuesSize);
+#if !USE_CONSERVATIVE_GC
for (int i = 0; i != inlineSize; ++i)
imp->values[i]->deref();
+#endif
+
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ for (int i = 0; i != inlineSize; ++i)
+ gcUnprotect(imp->values[i]);
+#endif
int overflowSize = size - inlineSize;
ValueImp **overflow = imp->overflow;
+#if !USE_CONSERVATIVE_GC
for (int i = 0; i != overflowSize; ++i)
overflow[i]->deref();
+#endif
+
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ for (int i = 0; i != overflowSize; ++i)
+ gcUnprotect(overflow[i]);
+#endif
}
void List::refValues()
int size = imp->size;
int inlineSize = MIN(size, inlineValuesSize);
+#if !USE_CONSERVATIVE_GC
for (int i = 0; i != inlineSize; ++i)
imp->values[i]->ref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ for (int i = 0; i != inlineSize; ++i)
+ gcProtect(imp->values[i]);
+#endif
int overflowSize = size - inlineSize;
ValueImp **overflow = imp->overflow;
+#if !USE_CONSERVATIVE_GC
for (int i = 0; i != overflowSize; ++i)
overflow[i]->ref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ for (int i = 0; i != overflowSize; ++i)
+ gcProtect(overflow[i]);
+#endif
}
void List::markValues()
#endif
if (imp->valueRefCount > 0) {
+#if !USE_CONSERVATIVE_GC
v->ref();
+#endif
+#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
+ gcProtect(v);
+#endif
}
if (i < inlineValuesSize) {
void ObjectImp::setInternalValue(ValueImp *v)
{
+#if !USE_CONSERVATIVE_GC
v->setGcAllowed();
+#endif
_internalValue = v;
}
void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr)
{
+#if !USE_CONSERVATIVE_GC
value->setGcAllowed();
+#endif
_prop.put(propertyName, value, attr);
}
inline void gcProtect(ValueImp *val)
{
-#if TEST_CONSERVATIVE_GC
+#if TEST_CONSERVATIVE_GC | USE_CONSERVATIVE_GC
ProtectedValues::increaseProtectCount(val);
#endif
}
inline void gcUnprotect(ValueImp *val)
{
-#if TEST_CONSERVATIVE_GC
+#if TEST_CONSERVATIVE_GC | USE_CONSERVATIVE_GC
ProtectedValues::decreaseProtectCount(val);
#endif
}
+
+ inline void gcProtectNullTolerant(ValueImp *val)
+ {
+ if (val) gcProtect(val);
+ }
+
+ inline void gcUnprotectNullTolerant(ValueImp *val)
+ {
+ if (val) gcUnprotect(val);
+ }
+
class ProtectedValue : public Value {
public:
ProtectedValue() : Value() {}
- ProtectedValue(const Value&v) : Value(v) { gcProtect(v.imp()); };
- ~ProtectedValue() { gcUnprotect(imp());}
+ ProtectedValue(const Value&v) : Value(v) { gcProtectNullTolerant(v.imp()); };
+ ~ProtectedValue() { gcUnprotectNullTolerant(imp());}
ProtectedValue& operator=(const Value &v)
{
ValueImp *old = imp();
Value::operator=(v);
- gcProtect(v.imp());
- gcUnprotect(old);
+ gcProtectNullTolerant(v.imp());
+ gcUnprotectNullTolerant(old);
return *this;
}
private:
class ProtectedObject : public Object {
public:
ProtectedObject() : Object() {}
- ProtectedObject(const Object&o) : Object(o) { gcProtect(o.imp()); };
- ~ProtectedObject() { gcUnprotect(imp());}
+ ProtectedObject(const Object&o) : Object(o) { gcProtectNullTolerant(o.imp()); };
+ ~ProtectedObject() { gcUnprotectNullTolerant(imp());}
ProtectedObject& operator=(const Object &o)
{
ValueImp *old = imp();
Object::operator=(o);
- gcProtect(o.imp());
- gcUnprotect(old);
+ gcProtectNullTolerant(o.imp());
+ gcUnprotectNullTolerant(old);
return *this;
}
private:
class ProtectedReference : public Reference {
public:
- ProtectedReference(const Reference&r) : Reference(r) { gcProtect(r.base.imp()); };
- ~ProtectedReference() { gcUnprotect(base.imp());}
+ ProtectedReference(const Reference&r) : Reference(r) { gcProtectNullTolerant(r.base.imp()); };
+ ~ProtectedReference() { gcUnprotectNullTolerant(base.imp());}
ProtectedReference& operator=(const Reference &r)
{
ValueImp *old = base.imp();
Reference::operator=(r);
- gcProtect(r.base.imp());
- gcUnprotect(old);
+ gcProtectNullTolerant(r.base.imp());
+ gcUnprotectNullTolerant(old);
return *this;
}
private:
int ProtectedValues::getProtectCount(ValueImp *k)
{
- if (!k)
- return 0;
-
if (!_table)
return 0;
void ProtectedValues::increaseProtectCount(ValueImp *k)
{
- if (!k)
- return;
+ assert(k);
if (!_table)
expand();
void ProtectedValues::decreaseProtectCount(ValueImp *k)
{
- if (!k)
- return;
+ assert(k);
unsigned hash = computeHash(k);
// or anything like that.
const unsigned PHI = 0x9e3779b9U;
+template <int size> static unsigned hash(ValueImp *pointer);
+
+template <> static inline unsigned hash<4>(ValueImp *pointer)
+{
+ int a = (int)PHI;
+ int b = (int)pointer;
+ int c = 0;
+
+ a -= b; a -= c; a ^= (c>>13);
+ b -= c; b -= a; b ^= (a<<8);
+ c -= a; c -= b; c ^= (b>>13);
+ a -= b; a -= c; a ^= (c>>12);
+ b -= c; b -= a; b ^= (a<<16);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>3);
+ b -= c; b -= a; b ^= (a<<10);
+ c -= a; c -= b; c ^= (b>>15);
+
+ return (unsigned)c;
+}
+
+template <> static inline unsigned hash<8>(ValueImp *pointer)
+{
+ int a = (int)PHI;
+ int b = (int)(long)pointer;
+ int c = (int)(((long)pointer >> 16) >> 16);
+
+ a -= b; a -= c; a ^= (c>>13);
+ b -= c; b -= a; b ^= (a<<8);
+ c -= a; c -= b; c ^= (b>>13);
+ a -= b; a -= c; a ^= (c>>12);
+ b -= c; b -= a; b ^= (a<<16);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>3);
+ b -= c; b -= a; b ^= (a<<10);
+ c -= a; c -= b; c ^= (b>>15);
+
+ return (unsigned)c;
+}
+
+
// This hash algorithm comes from:
// http://burtleburtle.net/bob/hash/hashfaq.html
// http://burtleburtle.net/bob/hash/doobs.html
unsigned ProtectedValues::computeHash(ValueImp *pointer)
{
- int length = sizeof(ValueImp *);
- char s[sizeof(ValueImp *)];
-
- memcpy((void *)s, (void *)&pointer, sizeof(ValueImp *));
-
- unsigned h = PHI;
- h += length;
- h += (h << 10);
- h ^= (h << 6);
-
- for (int i = 0; i < length; i++) {
- h += (unsigned char)s[i];
- h += (h << 10);
- h ^= (h << 6);
- }
-
- h += (h << 3);
- h ^= (h >> 11);
- h += (h << 15);
-
- if (h == 0)
- h = 0x80000000;
-
- return h;
+ return hash<sizeof(ValueImp *)>(pointer);
}
-
} // namespace
// ----------------------------- ValueImp -------------------------------------
+#if !USE_CONSERVATIVE_GC
ValueImp::ValueImp() :
refcount(0),
// Tell the garbage collector that this memory block corresponds to a real object now
{
//fprintf(stderr,"ValueImp::~ValueImp %p\n",(void*)this);
}
+#endif
#if TEST_CONSERVATIVE_GC
static bool conservativeMark = false;
void ValueImp::mark()
{
//fprintf(stderr,"ValueImp::mark %p\n",(void*)this);
-#if TEST_CONSERVATIVE_GC
+#if USE_CONSERVATIVE_GC
+ _marked = true;
+#elif TEST_CONSERVATIVE_GC
if (conservativeMark) {
_flags |= VI_CONSERVATIVE_MARKED;
} else {
bool ValueImp::marked() const
{
// Simple numbers are always considered marked.
-#if TEST_CONSERVATIVE_GC
+#if USE_CONSERVATIVE_GC
+ return SimpleNumber::is(this) || _marked;
+#elif TEST_CONSERVATIVE_GC
if (conservativeMark) {
return SimpleNumber::is(this) || (_flags & VI_CONSERVATIVE_MARKED);
} else {
#endif
}
+#if !USE_CONSERVATIVE_GC
void ValueImp::setGcAllowed()
{
//fprintf(stderr,"ValueImp::setGcAllowed %p\n",(void*)this);
if (!SimpleNumber::is(this))
_flags |= VI_GCALLOWED;
}
+#endif
void* ValueImp::operator new(size_t s)
{
// ------------------------------ Value ----------------------------------------
+#if !USE_CONSERVATIVE_GC
+
Value::Value(ValueImp *v)
{
rep = v;
}
return *this;
}
+#endif
// ------------------------------ Undefined ------------------------------------
#ifndef _KJS_VALUE_H_
#define _KJS_VALUE_H_
+#define USE_CONSERVATIVE_GC 0
#define TEST_CONSERVATIVE_GC 0
#ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
friend class Value;
friend class ContextImp;
public:
+#if USE_CONSERVATIVE_GC
+ ValueImp() : _marked(0) {}
+ virtual ~ValueImp() {}
+#else
ValueImp();
virtual ~ValueImp();
+#endif
+#if !USE_CONSERVATIVE_GC
ValueImp* ref() { if (!SimpleNumber::is(this)) refcount++; return this; }
bool deref() { if (SimpleNumber::is(this)) return false; else return (!--refcount); }
+#endif
virtual void mark();
bool marked() const;
void* operator new(size_t);
void operator delete(void*);
+#if !USE_CONSERVATIVE_GC
/**
* @internal
*
// Will crash if called on a simple number.
void setGcAllowedFast() { _flags |= VI_GCALLOWED; }
+#endif
double toInteger(ExecState *exec) const;
int32_t toInt32(ExecState *exec) const;
bool dispatchToUInt32(uint32_t&) const;
Object dispatchToObject(ExecState *exec) const;
+#if !USE_CONSERVATIVE_GC
unsigned short int refcount;
+#endif
private:
- unsigned short int _flags;
-
virtual Type type() const = 0;
// The conversion operations
virtual Object toObject(ExecState *exec) const = 0;
virtual bool toUInt32(unsigned&) const;
+#if USE_CONSERVATIVE_GC
+ bool _marked;
+#else
+ unsigned short int _flags;
+
enum {
VI_MARKED = 1,
VI_GCALLOWED = 2,
VI_CREATED = 4
#if TEST_CONSERVATIVE_GC
, VI_CONSERVATIVE_MARKED = 8
-#endif
+#endif // TEST_CONSERVATIVE_GC
}; // VI means VALUEIMPL
+#endif // USE_CONSERVATIVE_GC
// Give a compile time error if we try to copy one of these.
ValueImp(const ValueImp&);
class Value {
public:
Value() : rep(0) { }
+#if USE_CONSERVATIVE_GC
+ explicit Value(ValueImp *v) : rep(v) {}
+ Value(const Value &v) : rep (v.rep) {}
+ ~Value() {}
+ Value& operator=(const Value &v) { rep = v.rep; return *this; }
+#else
explicit Value(ValueImp *v);
Value(const Value &v);
~Value();
-
Value& operator=(const Value &v);
+#endif
+
bool isNull() const { return rep == 0; }
ValueImp *imp() const { return rep; }
+2004-04-25 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin.
+
+ * khtml/ecma/kjs_events.cpp:
+ (JSLazyEventListener::parseCode): Make sure to protect the
+ permanent "event" string object.
+
2004-05-05 David Hyatt <hyatt@apple.com>
Fixes for 3637924, 3643356, and 3558513, all crashes in recalcStyle. Make sure the tree is always in a
KJS::Object constr = interpreter->builtinFunction();
KJS::List args;
- static KJS::String eventString("event");
+ static ProtectedValue eventString = KJS::String("event");
args.append(eventString);
args.append(KJS::String(code));