2010-07-13 Andreas Kling <andreas.kling@nokia.com>

        Reviewed by Darin Adler.

        Avoid slow-path for put() in Array.splice()
        https://bugs.webkit.org/show_bug.cgi?id=41920

        Defer creation of the returned array until its final size is known
        to avoid growing it while adding elements.

        * runtime/JSArray.cpp:
        (JSC::JSArray::JSArray): Add two modes of creation, CreateInitialized (old)
        and CreateCompact (which should only be used when constructing arrays whose
        size and contents are known at the time of creation.)
        (JSC::JSArray::setLength): Skip first consistency check if in CreateCompact
        initialization mode. (Only applies to non-empty arrays.)
        (JSC::JSArray::checkConsistency): Build fix (JSValue::type() is gone)
        * runtime/JSArray.h:
        (JSC::JSArray::uncheckedSetIndex): Added for fast initialization of compact
        arrays. Does no bounds or other sanity checking.
        * runtime/ArrayPrototype.cpp:
        (JSC::arrayProtoFuncSplice): Optimized creation of the returned JSArray.
        * runtime/ArrayConstructor.cpp:
        (JSC::constructArrayWithSizeQuirk): Pass CreateInitialized to ctor.
        * runtime/JSGlobalObject.h:
        (JSC::constructEmptyArray): Pass CreateInitialized to ctor.
        * runtime/RegExpConstructor.cpp:
        (JSC::RegExpMatchesArray::RegExpMatchesArray): Pass CreateInitialized to ctor.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@63268 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 40b4ad33
2010-07-13 Andreas Kling <andreas.kling@nokia.com>
Reviewed by Darin Adler.
Avoid slow-path for put() in Array.splice()
https://bugs.webkit.org/show_bug.cgi?id=41920
Defer creation of the returned array until its final size is known
to avoid growing it while adding elements.
* runtime/JSArray.cpp:
(JSC::JSArray::JSArray): Add two modes of creation, CreateInitialized (old)
and CreateCompact (which should only be used when constructing arrays whose
size and contents are known at the time of creation.)
(JSC::JSArray::setLength): Skip first consistency check if in CreateCompact
initialization mode. (Only applies to non-empty arrays.)
(JSC::JSArray::checkConsistency): Build fix (JSValue::type() is gone)
* runtime/JSArray.h:
(JSC::JSArray::uncheckedSetIndex): Added for fast initialization of compact
arrays. Does no bounds or other sanity checking.
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncSplice): Optimized creation of the returned JSArray.
* runtime/ArrayConstructor.cpp:
(JSC::constructArrayWithSizeQuirk): Pass CreateInitialized to ctor.
* runtime/JSGlobalObject.h:
(JSC::constructEmptyArray): Pass CreateInitialized to ctor.
* runtime/RegExpConstructor.cpp:
(JSC::RegExpMatchesArray::RegExpMatchesArray): Pass CreateInitialized to ctor.
2010-07-13 Gavin Barraclough <barraclough@apple.com>
Reviewed by Oliver Hunt.
......
......@@ -58,7 +58,7 @@ static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgLi
uint32_t n = args.at(0).toUInt32(exec);
if (n != args.at(0).toNumber(exec))
return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer."));
return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n);
return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n, CreateInitialized);
}
// otherwise the array is constructed with the arguments in it
......
......@@ -547,8 +547,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
JSObject* thisObj = thisValue.toThisObject(exec);
// 15.4.4.12
JSArray* resObj = constructEmptyArray(exec);
JSValue result = resObj;
// FIXME: Firefox returns an empty array.
if (!exec->argumentCount())
......@@ -569,10 +567,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
else
deleteCount = length - begin;
for (unsigned k = 0; k < deleteCount; k++) {
if (JSValue v = getProperty(exec, thisObj, k + begin))
resObj->put(exec, k, v);
}
JSArray* resObj = new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact);
JSValue result = resObj;
for (unsigned k = 0; k < deleteCount; k++)
resObj->uncheckedSetIndex(k, getProperty(exec, thisObj, k + begin));
resObj->setLength(deleteCount);
unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
......
......@@ -33,8 +33,6 @@
#include <wtf/OwnPtr.h>
#include <Operations.h>
#define CHECK_ARRAY_CONSISTENCY 0
using namespace std;
using namespace WTF;
......@@ -141,22 +139,37 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure)
checkConsistency();
}
JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength)
JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength, ArrayCreationMode creationMode)
: JSObject(structure)
{
unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX);
unsigned initialCapacity;
if (creationMode == CreateCompact)
initialCapacity = initialLength;
else
initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX);
m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity)));
m_storage->m_length = initialLength;
m_vectorLength = initialCapacity;
m_storage->m_numValuesInVector = 0;
m_storage->m_sparseValueMap = 0;
m_storage->subclassData = 0;
m_storage->reportedMapCapacity = 0;
JSValue* vector = m_storage->m_vector;
for (size_t i = 0; i < initialCapacity; ++i)
vector[i] = JSValue();
if (creationMode == CreateCompact) {
#if CHECK_ARRAY_CONSISTENCY
m_storage->m_inCompactInitialization = !!initialCapacity;
#endif
m_storage->m_length = 0;
m_storage->m_numValuesInVector = initialCapacity;
} else {
#if CHECK_ARRAY_CONSISTENCY
m_storage->m_inCompactInitialization = false;
#endif
m_storage->m_length = initialLength;
m_storage->m_numValuesInVector = 0;
JSValue* vector = m_storage->m_vector;
for (size_t i = 0; i < initialCapacity; ++i)
vector[i] = JSValue();
}
checkConsistency();
......@@ -175,6 +188,9 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list)
m_storage->m_sparseValueMap = 0;
m_storage->subclassData = 0;
m_storage->reportedMapCapacity = 0;
#if CHECK_ARRAY_CONSISTENCY
m_storage->m_inCompactInitialization = false;
#endif
size_t i = 0;
ArgList::const_iterator end = list.end();
......@@ -524,7 +540,12 @@ bool JSArray::increaseVectorLength(unsigned newLength)
void JSArray::setLength(unsigned newLength)
{
checkConsistency();
#if CHECK_ARRAY_CONSISTENCY
if (!m_storage->m_inCompactInitialization)
checkConsistency();
else
m_storage->m_inCompactInitialization = false;
#endif
ArrayStorage* storage = m_storage;
......@@ -1045,7 +1066,7 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
if (JSValue value = m_storage->m_vector[i]) {
ASSERT(i < m_storage->m_length);
if (type != DestructorConsistencyCheck)
value->type(); // Likely to crash if the object was deallocated.
value.isUndefined(); // Likely to crash if the object was deallocated.
++numValuesInVector;
} else {
if (type == SortConsistencyCheck)
......@@ -1064,7 +1085,7 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
ASSERT(index <= MAX_ARRAY_INDEX);
ASSERT(it->second);
if (type != DestructorConsistencyCheck)
it->second->type(); // Likely to crash if the object was deallocated.
it->second.isUndefined(); // Likely to crash if the object was deallocated.
}
}
}
......
......@@ -23,6 +23,8 @@
#include "JSObject.h"
#define CHECK_ARRAY_CONSISTENCY 0
namespace JSC {
typedef HashMap<unsigned, JSValue> SparseArrayValueMap;
......@@ -33,16 +35,29 @@ namespace JSC {
SparseArrayValueMap* m_sparseValueMap;
void* subclassData; // A JSArray subclass can use this to fill the vector lazily.
size_t reportedMapCapacity;
#if CHECK_ARRAY_CONSISTENCY
bool m_inCompactInitialization;
#endif
JSValue m_vector[1];
};
// The CreateCompact creation mode is used for fast construction of arrays
// whose size and contents are known at time of creation.
//
// There are two obligations when using this mode:
//
// - uncheckedSetIndex() must be used when initializing the array.
// - setLength() must be called after initialization.
enum ArrayCreationMode { CreateCompact, CreateInitialized };
class JSArray : public JSObject {
friend class JIT;
friend class Walker;
public:
explicit JSArray(NonNullPassRefPtr<Structure>);
JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength);
JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength, ArrayCreationMode);
JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues);
virtual ~JSArray();
......@@ -83,6 +98,15 @@ namespace JSC {
x = v;
}
void uncheckedSetIndex(unsigned i, JSValue v)
{
ASSERT(canSetIndex(i));
#if CHECK_ARRAY_CONSISTENCY
ASSERT(m_storage->m_inCompactInitialization);
#endif
m_storage->m_vector[i] = v;
}
void fillArgList(ExecState*, MarkedArgumentBuffer&);
void copyToRegisters(ExecState*, Register*, uint32_t);
......
......@@ -457,7 +457,7 @@ namespace JSC {
inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
{
return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength);
return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
}
inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
......
......@@ -106,7 +106,7 @@ RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObje
}
RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
: JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1)
: JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1, CreateInitialized)
{
RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
d->input = data->lastInput;
......
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