Commit 1d72f777 authored by ggaren@apple.com's avatar ggaren@apple.com

2008-07-02 Geoffrey Garen <ggaren@apple.com>

        Reviewed by Oliver Hunt.

        Optimized a[n] get for cases where a is an array or a string, and a[n]
        put for cases where a is an array.
        
        SunSpider says 9.0% faster.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34964 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 08d1e583
2008-07-02 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
Optimized a[n] get for cases where a is an array or a string, and a[n]
put for cases where a is an array.
SunSpider says 9.0% faster.
2008-07-02 Kevin McCullough <kmccullough@apple.com>
Reviewed by Darin.
......@@ -45,6 +45,7 @@
#include "RegExpObject.h"
#include "RegExpPrototype.h"
#include "Register.h"
#include "collector.h"
#include "debugger.h"
#include "operations.h"
#include <stdio.h>
......@@ -475,6 +476,19 @@ Machine::Machine()
, m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
{
privateExecute(InitializeAndReturn);
// Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
void* storage = fastMalloc(sizeof(CollectorBlock));
JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
m_jsArrayVptr = jsArray->vptr();
jsArray->~JSCell();
JSString* jsString = new (storage) JSString("");
m_jsStringVptr = jsString->vptr();
jsString->~JSCell();
fastFree(storage);
}
void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
......@@ -1834,9 +1848,18 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
unsigned i;
bool isUInt32 = JSImmediate::getUInt32(subscript, i);
if (LIKELY(isUInt32))
result = baseValue->get(exec, i);
else {
if (LIKELY(isUInt32)) {
if (isJSArray(baseValue)) {
JSArray* jsArray = static_cast<JSArray*>(baseValue);
if (jsArray->canGetIndex(i))
result = jsArray->getIndex(i);
else
result = jsArray->JSArray::get(exec, i);
} else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
else
result = baseValue->get(exec, i);
} else {
Identifier property(exec, subscript->toString(exec));
result = baseValue->get(exec, property);
}
......@@ -1867,9 +1890,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
unsigned i;
bool isUInt32 = JSImmediate::getUInt32(subscript, i);
if (LIKELY(isUInt32))
baseValue->put(exec, i, r[value].u.jsValue);
else {
if (LIKELY(isUInt32)) {
if (isJSArray(baseValue)) {
JSArray* jsArray = static_cast<JSArray*>(baseValue);
if (jsArray->canSetIndex(i))
jsArray->setIndex(i, r[value].u.jsValue);
else
jsArray->JSArray::put(exec, i, r[value].u.jsValue);
} else
baseValue->put(exec, i, r[value].u.jsValue);
} else {
Identifier property(exec, subscript->toString(exec));
if (!exec->hadException()) // Don't put to an object if toString threw an exception.
baseValue->put(exec, property, r[value].u.jsValue);
......
......@@ -29,6 +29,8 @@
#ifndef Machine_h
#define Machine_h
#include "JSCell.h"
#include "JSValue.h"
#include "Opcode.h"
#include "RegisterFile.h"
#include <kjs/list.h>
......@@ -140,6 +142,9 @@ namespace KJS {
JSValue* checkTimeout(JSGlobalObject*);
void resetTimeoutCheck();
bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
int m_reentryDepth;
unsigned m_timeoutTime;
unsigned m_timeAtLastCheckTimeout;
......@@ -148,6 +153,9 @@ namespace KJS {
unsigned m_ticksUntilNextTimeoutCheck;
RegisterFile m_registerFile;
void* m_jsArrayVptr;
void* m_jsStringVptr;
#if HAVE(COMPUTED_GOTO)
Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
......
......@@ -34,16 +34,6 @@ using namespace std;
namespace KJS {
typedef HashMap<unsigned, JSValue*> SparseArrayValueMap;
struct ArrayStorage {
unsigned m_vectorLength;
unsigned m_numValuesInVector;
SparseArrayValueMap* m_sparseValueMap;
void* lazyCreationData; // An JSArray subclass can use this to fill the vector lazily.
JSValue* m_vector[1];
};
// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
static const unsigned maxArrayIndex = 0xFFFFFFFEU;
......@@ -81,7 +71,7 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
#endif
JSArray::JSArray(JSObject* prototype, unsigned initialLength)
JSArray::JSArray(JSValue* prototype, unsigned initialLength)
: JSObject(prototype)
{
unsigned initialCapacity = min(initialLength, sparseArrayCutoff);
......
......@@ -26,11 +26,19 @@
namespace KJS {
struct ArrayStorage;
typedef HashMap<unsigned, JSValue*> SparseArrayValueMap;
struct ArrayStorage {
unsigned m_vectorLength;
unsigned m_numValuesInVector;
SparseArrayValueMap* m_sparseValueMap;
void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily.
JSValue* m_vector[1];
};
class JSArray : public JSObject {
public:
JSArray(JSObject* prototype, unsigned initialLength);
JSArray(JSValue* prototype, unsigned initialLength);
JSArray(JSObject* prototype, const ArgList& initialValues);
virtual ~JSArray();
......@@ -46,6 +54,20 @@ namespace KJS {
void sort(ExecState*);
void sort(ExecState*, JSValue* compareFunction, CallType, const CallData&);
bool canGetIndex(unsigned i) { return i < m_fastAccessCutoff; }
JSValue* getIndex(unsigned i)
{
ASSERT(canGetIndex(i));
return m_storage->m_vector[i];
}
bool canSetIndex(unsigned i) { return i < m_fastAccessCutoff; }
JSValue* setIndex(unsigned i, JSValue* v)
{
ASSERT(canSetIndex(i));
return m_storage->m_vector[i] = v;
}
protected:
virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
......
......@@ -36,6 +36,7 @@ class JSCell : public JSValue {
friend class JSValue;
friend class JSNumberCell;
friend class JSString;
friend class Machine;
private:
JSCell();
virtual ~JSCell();
......@@ -74,6 +75,7 @@ public:
// Garbage collection.
void* operator new(size_t, ExecState*);
void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
virtual void mark();
bool marked() const;
......@@ -88,6 +90,7 @@ public:
virtual UString toThisString(ExecState*) const;
virtual JSString* toThisJSString(ExecState*);
virtual JSValue* getJSNumber();
void* vptr() { return *reinterpret_cast<void**>(this); }
private:
// Base implementation, but for non-object classes implements getPropertySlot.
......
......@@ -43,6 +43,13 @@ namespace KJS {
bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
bool getStringPropertySlot(unsigned propertyName, PropertySlot&);
bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); }
JSValue* getIndex(ExecState* exec, unsigned i)
{
ASSERT(canGetIndex(i));
return new (exec) JSString(m_value.substr(i, 1));
}
private:
virtual JSType type() const { return StringType; }
......
......@@ -52,6 +52,7 @@ struct Instruction;
class JSValue : Noncopyable {
friend class JSCell; // so it can derive from this class
friend class Heap; // so it can call asCell()
friend class Machine; // so it can call asCell()
private:
JSValue();
virtual ~JSValue();
......
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