+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.
#include "RegExpObject.h"
#include "RegExpPrototype.h"
#include "Register.h"
+#include "collector.h"
#include "debugger.h"
#include "operations.h"
#include <stdio.h>
, 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)
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);
}
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);
#ifndef Machine_h
#define Machine_h
+#include "JSCell.h"
+#include "JSValue.h"
#include "Opcode.h"
#include "RegisterFile.h"
#include <kjs/list.h>
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;
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
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;
#endif
-JSArray::JSArray(JSObject* prototype, unsigned initialLength)
+JSArray::JSArray(JSValue* prototype, unsigned initialLength)
: JSObject(prototype)
{
unsigned initialCapacity = min(initialLength, sparseArrayCutoff);
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();
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);
friend class JSValue;
friend class JSNumberCell;
friend class JSString;
+ friend class Machine;
private:
JSCell();
virtual ~JSCell();
// Garbage collection.
void* operator new(size_t, ExecState*);
+ void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
virtual void mark();
bool marked() const;
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.
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; }
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();