Commit 52000e7d authored by oliver@apple.com's avatar oliver@apple.com

Devirtualise marking

https://bugs.webkit.org/show_bug.cgi?id=28294

Reviewed by Maciej Stachowiak.

Add a bit to TypeInfo to indicate that an object uses the standard
JSObject::markChildren method.  This allows us to devirtualise marking
of most objects (though a branch is still needed).  We also add a branch
to identify arrays thus devirtualising marking in that case as well.

In order to make the best use of this devirtualisation I've also reworked
the MarkStack::drain() logic to make the iteration more efficient.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@47267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ef5f8167
......@@ -41,7 +41,7 @@ public:
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot));
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot | HasDefaultMark));
}
private:
......
......@@ -41,7 +41,7 @@ public:
// refactor the code so this override isn't necessary
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot));
return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
}
private:
......
2009-08-13 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
Devirtualise marking
https://bugs.webkit.org/show_bug.cgi?id=28294
Add a bit to TypeInfo to indicate that an object uses the standard
JSObject::markChildren method. This allows us to devirtualise marking
of most objects (though a branch is still needed). We also add a branch
to identify arrays thus devirtualising marking in that case as well.
In order to make the best use of this devirtualisation I've also reworked
the MarkStack::drain() logic to make the iteration more efficient.
* API/JSCallbackConstructor.h:
(JSC::JSCallbackConstructor::createStructure):
* API/JSCallbackFunction.h:
(JSC::JSCallbackFunction::createStructure):
* JavaScriptCore.exp:
* runtime/BooleanObject.h:
(JSC::BooleanObject::createStructure):
* runtime/FunctionPrototype.h:
(JSC::FunctionPrototype::createStructure):
* runtime/InternalFunction.h:
(JSC::InternalFunction::createStructure):
* runtime/JSAPIValueWrapper.h:
(JSC::JSAPIValueWrapper::JSAPIValueWrapper):
* runtime/JSArray.cpp:
(JSC::JSArray::markChildren):
* runtime/JSArray.h:
(JSC::JSArray::markChildrenDirect):
(JSC::MarkStack::drain):
* runtime/JSByteArray.cpp:
(JSC::JSByteArray::createStructure):
* runtime/JSCell.h:
(JSC::MarkStack::append):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSNumberCell.h:
(JSC::JSNumberCell::createStructure):
* runtime/JSONObject.h:
(JSC::JSONObject::createStructure):
* runtime/JSObject.cpp:
(JSC::JSObject::markChildren):
* runtime/JSObject.h:
(JSC::JSObject::markChildrenDirect):
(JSC::JSObject::createStructure):
* runtime/JSString.h:
(JSC::JSString::createStructure):
* runtime/JSType.h:
(JSC::):
* runtime/MarkStack.h:
(JSC::MarkStack::MarkStack):
(JSC::MarkStack::MarkSet::MarkSet):
(JSC::MarkStack::MarkStackArray::last):
* runtime/MathObject.h:
(JSC::MathObject::createStructure):
* runtime/NumberConstructor.h:
(JSC::NumberConstructor::createStructure):
* runtime/NumberObject.h:
(JSC::NumberObject::createStructure):
* runtime/RegExpConstructor.h:
(JSC::RegExpConstructor::createStructure):
* runtime/RegExpObject.h:
(JSC::RegExpObject::createStructure):
* runtime/StringObjectThatMasqueradesAsUndefined.h:
(JSC::StringObjectThatMasqueradesAsUndefined::createStructure):
* runtime/TypeInfo.h:
(JSC::TypeInfo::hasDefaultMark):
2009-08-13 Darin Adler <darin@apple.com>
Reviewed by Mark Rowe.
......
......@@ -262,6 +262,7 @@ __ZN3JSC9MarkStack10s_pageSizeE
__ZN3JSC9MarkStack12releaseStackEPvm
__ZN3JSC9MarkStack13allocateStackEm
__ZN3JSC9MarkStack18initializePagesizeEv
__ZN3JSC9MarkStack5drainEv
__ZN3JSC9Structure17stopIgnoringLeaksEv
__ZN3JSC9Structure18startIgnoringLeaksEv
__ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
......
......@@ -31,6 +31,11 @@ namespace JSC {
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
}
};
BooleanObject* asBooleanObject(JSValue);
......
......@@ -34,7 +34,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot));
return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
}
private:
......
......@@ -42,7 +42,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot));
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot | HasDefaultMark));
}
protected:
......
......@@ -54,6 +54,7 @@ namespace JSC {
: JSCell(exec->globalData().apiWrapperStructure.get())
, m_value(value)
{
ASSERT(!value.isCell());
}
JSValue m_value;
......
......@@ -602,18 +602,7 @@ void JSArray::push(ExecState* exec, JSValue value)
void JSArray::markChildren(MarkStack& markStack)
{
JSObject::markChildren(markStack);
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength);
markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
markStack.append(it->second);
}
markChildrenDirect(markStack);
}
static int compareNumbersForQSort(const void* a, const void* b)
......
......@@ -82,6 +82,8 @@ namespace JSC {
{
return Structure::create(prototype, TypeInfo(ObjectType));
}
inline void markChildrenDirect(MarkStack& markStack);
protected:
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
......@@ -125,6 +127,78 @@ namespace JSC {
inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; }
void JSArray::markChildrenDirect(MarkStack& markStack) {
JSObject::markChildrenDirect(markStack);
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = std::min(storage->m_length, storage->m_vectorLength);
markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
markStack.append(it->second);
}
}
inline void MarkStack::drain()
{
while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
while (!m_markSets.isEmpty() && m_values.size() < 50) {
ASSERT(!m_markSets.isEmpty());
MarkSet& current = m_markSets.last();
ASSERT(current.m_values);
JSValue* end = current.m_end;
ASSERT(current.m_values);
ASSERT(current.m_values != end);
findNextUnmarkedNullValue:
ASSERT(current.m_values != end);
JSValue v = *current.m_values;
current.m_values++;
if (!v || v.marked()) {
if (current.m_values == end) {
m_markSets.removeLast();
continue;
}
goto findNextUnmarkedNullValue;
}
JSCell* currentCell = v.asCell();
currentCell->markCellDirect();
if (currentCell->structure()->typeInfo().type() < CompoundType) {
if (current.m_values == end) {
m_markSets.removeLast();
continue;
}
goto findNextUnmarkedNullValue;
}
if (current.m_values == end)
m_markSets.removeLast();
if (currentCell->structure()->typeInfo().hasDefaultMark())
static_cast<JSObject*>(currentCell)->markChildrenDirect(*this);
else if (currentCell->vptr() == m_jsArrayVPtr)
static_cast<JSArray*>(currentCell)->markChildrenDirect(*this);
else
currentCell->markChildren(*this);
}
while (!m_values.isEmpty()) {
JSCell* current = m_values.removeLast();
ASSERT(current->marked());
if (current->structure()->typeInfo().hasDefaultMark())
static_cast<JSObject*>(current)->markChildrenDirect(*this);
else if (current->vptr() == m_jsArrayVPtr)
static_cast<JSArray*>(current)->markChildrenDirect(*this);
else
current->markChildren(*this);
}
}
// printf("virtual: %d nonvirtual: %d\n", virtualMark, nonVirtualMark);
}
} // namespace JSC
#endif // JSArray_h
......@@ -45,7 +45,7 @@ JSByteArray::JSByteArray(ExecState* exec, PassRefPtr<Structure> structure, ByteA
PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype)
{
PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType));
PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark));
return result;
}
......
......@@ -379,30 +379,6 @@ namespace JSC {
if (cell->structure()->typeInfo().type() >= CompoundType)
m_values.append(cell);
}
inline void MarkStack::drain() {
while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
while ((!m_markSets.isEmpty()) && m_values.size() < 50) {
const MarkSet& current = m_markSets.removeLast();
JSValue* ptr = current.m_values;
JSValue* end = current.m_end;
if (current.m_properties == NoNullValues) {
while (ptr != end)
append(*ptr++);
} else {
while (ptr != end) {
if (JSValue value = *ptr++)
append(value);
}
}
}
while (!m_values.isEmpty()) {
JSCell* current = m_values.removeLast();
ASSERT(current->marked());
current->markChildren(*this);
}
}
}
} // namespace JSC
#endif // JSCell_h
......@@ -146,6 +146,7 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
, dynamicGlobalObject(0)
, scopeNodeBeingReparsed(0)
, firstStringifierToMark(0)
, markStack(vptrSet.jsArrayVPtr)
{
#if PLATFORM(MAC)
startProfilerServerIfNeeded();
......
......@@ -84,7 +84,7 @@ namespace JSC {
#endif
}
static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, NeedsThisConversion)); }
static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, NeedsThisConversion | HasDefaultMark)); }
private:
JSNumberCell(JSGlobalData* globalData, double value)
......
......@@ -41,7 +41,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType));
return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark));
}
static void markStringifiers(MarkStack&, Stringifier*);
......
......@@ -37,26 +37,6 @@
#include <math.h>
#include <wtf/Assertions.h>
#define JSOBJECT_MARK_TRACING 0
#if JSOBJECT_MARK_TRACING
#define JSOBJECT_MARK_BEGIN() \
static int markStackDepth = 0; \
for (int i = 0; i < markStackDepth; i++) \
putchar('-'); \
printf("%s (%p)\n", className().UTF8String().c_str(), this); \
markStackDepth++; \
#define JSOBJECT_MARK_END() \
markStackDepth--;
#else // JSOBJECT_MARK_TRACING
#define JSOBJECT_MARK_BEGIN()
#define JSOBJECT_MARK_END()
#endif // JSOBJECT_MARK_TRACING
namespace JSC {
......@@ -64,16 +44,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSObject);
void JSObject::markChildren(MarkStack& markStack)
{
JSOBJECT_MARK_BEGIN();
JSCell::markChildren(markStack);
m_structure->markAggregate(markStack);
PropertyStorage storage = propertyStorage();
size_t storageSize = m_structure->propertyStorageSize();
markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
JSOBJECT_MARK_END();
markChildrenDirect(markStack);
}
UString JSObject::className() const
......
......@@ -27,7 +27,9 @@
#include "ClassInfo.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
#include "JSCell.h"
#include "JSNumberCell.h"
#include "MarkStack.h"
#include "PropertySlot.h"
#include "PutPropertySlot.h"
#include "ScopeChain.h"
......@@ -74,6 +76,7 @@ namespace JSC {
explicit JSObject(PassRefPtr<Structure>);
virtual void markChildren(MarkStack&);
ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
// The inline virtual destructor cannot be the first virtual function declared
// in the class as it results in the vtable being generated as a weak symbol
......@@ -201,7 +204,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot));
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
}
private:
......@@ -627,6 +630,16 @@ ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_
m_externalStorage = newPropertyStorage;
}
ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
{
JSCell::markChildren(markStack);
m_structure->markAggregate(markStack);
PropertyStorage storage = propertyStorage();
size_t storageSize = m_structure->propertyStorageSize();
markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
}
} // namespace JSC
#endif // JSObject_h
......@@ -90,7 +90,7 @@ namespace JSC {
bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); }
JSString* getIndex(JSGlobalData*, unsigned);
static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion)); }
static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion | HasDefaultMark)); }
private:
enum VPtrStealingHackType { VPtrStealingHack };
......
......@@ -33,7 +33,6 @@ namespace JSC {
NumberType = 3,
NullType = 4,
StringType = 5,
// The CompoundType value must come before any JSType that may have children
CompoundType = 6,
ObjectType = 7,
......
......@@ -31,15 +31,15 @@
#include <wtf/Noncopyable.h>
namespace JSC {
class JSGlobalData;
class Register;
enum MarkSetProperties { MayContainNullValues, NoNullValues };
class MarkStack : Noncopyable {
public:
MarkStack()
: m_markSets()
, m_values()
MarkStack(void* jsArrayVPtr)
: m_jsArrayVPtr(jsArrayVPtr)
{
}
......@@ -82,6 +82,7 @@ namespace JSC {
, m_end(end)
, m_properties(properties)
{
ASSERT(values);
}
JSValue* m_values;
JSValue* m_end;
......@@ -136,6 +137,12 @@ namespace JSC {
ASSERT(m_top);
return m_data[--m_top];
}
inline T& last()
{
ASSERT(m_top);
return m_data[m_top - 1];
}
inline bool isEmpty()
{
......@@ -169,6 +176,7 @@ namespace JSC {
T* m_data;
};
void* m_jsArrayVPtr;
MarkStackArray<MarkSet> m_markSets;
MarkStackArray<JSCell*> m_values;
static size_t s_pageSize;
......
......@@ -36,7 +36,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType));
return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark));
}
};
......
......@@ -38,7 +38,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance));
return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasDefaultMark));
}
enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
......
......@@ -30,6 +30,11 @@ namespace JSC {
explicit NumberObject(PassRefPtr<Structure>);
static const ClassInfo info;
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
}
private:
virtual const ClassInfo* classInfo() const { return &info; }
......
......@@ -36,7 +36,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance));
return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance | HasDefaultMark));
}
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
......
......@@ -48,7 +48,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType));
return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark));
}
private:
......
......@@ -44,7 +44,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
return Structure::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined));
return Structure::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined | HasDefaultMark));
}
virtual bool toBoolean(ExecState*) const { return false; }
......
......@@ -38,6 +38,7 @@ namespace JSC {
static const unsigned ImplementsDefaultHasInstance = 1 << 3;
static const unsigned NeedsThisConversion = 1 << 4;
static const unsigned HasStandardGetOwnPropertySlot = 1 << 5;
static const unsigned HasDefaultMark = 1 << 6;
class TypeInfo {
friend class JIT;
......@@ -59,7 +60,7 @@ namespace JSC {
bool overridesHasInstance() const { return m_flags & OverridesHasInstance; }
bool needsThisConversion() const { return m_flags & NeedsThisConversion; }
bool hasStandardGetOwnPropertySlot() const { return m_flags & HasStandardGetOwnPropertySlot; }
bool hasDefaultMark() const { return m_flags & HasDefaultMark; }
unsigned flags() const { return m_flags; }
private:
......
2009-08-13 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
Devirtualise marking
https://bugs.webkit.org/show_bug.cgi?id=28294
Continue to jump through hoops to deal with the exposed marking routines
in JavaScriptGlue.
* JSValueWrapper.cpp:
(JSValueWrapper::JSObjectMark):
2009-08-07 Oliver Hunt <oliver@apple.com>
Reviewed by Sam Weinig.
......
......@@ -29,6 +29,7 @@
#include "config.h"
#include "JSValueWrapper.h"
#include "JSRun.h"
#include <JavaScriptCore/JSArray.h>
#include <JavaScriptCore/PropertyNameArray.h>
#include <pthread.h>
......@@ -197,7 +198,10 @@ void JSValueWrapper::JSObjectMark(void *data)
if (ptr && !ptr->fValue.get().marked())
{
// This results in recursive marking but will be otherwise safe and correct.
MarkStack markStack;
// We claim the array vptr is 0 because we don't have access to it here, and
// claiming 0 is functionally harmless -- it merely means that we can't
// devirtualise marking of arrays when recursing from this point.
MarkStack markStack(0);
markStack.append(ptr->fValue.get());
markStack.drain();
}
......
2009-08-13 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
Devirtualise marking
https://bugs.webkit.org/show_bug.cgi?id=28294
Make sure we override the JSObject createStructure method on those
objects that have custom marking routines.
* bindings/scripts/CodeGeneratorJS.pm:
2009-08-13 Darin Adler <darin@apple.com>
Reviewed by Mark Rowe.
......@@ -664,6 +664,12 @@ sub GenerateHeader
push(@headerContent, " virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n");
push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"};
push(@headerContent,
" static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)\n" .
" {\n" .
" return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType" . ($dataNode->extendedAttributes->{"CustomMarkFunction"} ? "" : ", JSC::HasDefaultMark") . "));\n" .
" }\n");
} elsif ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
push(@headerContent,
" static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)\n" .
" {\n" .
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment