Commit 4fab8113 authored by mjs@apple.com's avatar mjs@apple.com

2008-09-10 Maciej Stachowiak <mjs@apple.com>

        Reviewed by Oliver.
        
        - enable polymorphic inline caching of properties of primitives
        
        1.012x speedup on SunSpider.

        We create special structure IDs for JSString and
        JSNumberCell. Unlike normal structure IDs, these cannot hold the
        true prototype. Due to JS autoboxing semantics, the prototype used
        when looking up string or number properties depends on the lexical
        global object of the call site, not the creation site. Thus we
        enable StructureIDs to handle this quirk for primitives.
        
        Everything else should be straightforward.
        
        * VM/CTI.cpp:
        (JSC::CTI::privateCompileGetByIdProto):
        (JSC::CTI::privateCompileGetByIdChain):
        * VM/CTI.h:
        (JSC::CTI::compileGetByIdProto):
        (JSC::CTI::compileGetByIdChain):
        * VM/JSPropertyNameIterator.h:
        (JSC::JSPropertyNameIterator::JSPropertyNameIterator):
        * VM/Machine.cpp:
        (JSC::Machine::Machine):
        (JSC::cachePrototypeChain):
        (JSC::Machine::tryCachePutByID):
        (JSC::Machine::tryCacheGetByID):
        (JSC::Machine::privateExecute):
        (JSC::Machine::tryCTICachePutByID):
        (JSC::Machine::tryCTICacheGetByID):
        * kjs/GetterSetter.h:
        (JSC::GetterSetter::GetterSetter):
        * kjs/JSCell.h:
        * kjs/JSGlobalData.cpp:
        (JSC::JSGlobalData::JSGlobalData):
        * kjs/JSGlobalData.h:
        * kjs/JSGlobalObject.h:
        (JSC::StructureID::prototypeForLookup):
        * kjs/JSNumberCell.h:
        (JSC::JSNumberCell::JSNumberCell):
        (JSC::jsNumberCell):
        * kjs/JSObject.h:
        (JSC::JSObject::prototype):
        * kjs/JSString.cpp:
        (JSC::jsString):
        (JSC::jsSubstring):
        (JSC::jsOwnedString):
        * kjs/JSString.h:
        (JSC::JSString::JSString):
        (JSC::JSString::):
        (JSC::jsSingleCharacterString):
        (JSC::jsSingleCharacterSubstring):
        (JSC::jsNontrivialString):
        * kjs/SmallStrings.cpp:
        (JSC::SmallStrings::createEmptyString):
        (JSC::SmallStrings::createSingleCharacterString):
        * kjs/StructureID.cpp:
        (JSC::StructureID::StructureID):
        (JSC::StructureID::addPropertyTransition):
        (JSC::StructureID::getterSetterTransition):
        (JSC::StructureIDChain::StructureIDChain):
        * kjs/StructureID.h:
        (JSC::StructureID::create):
        (JSC::StructureID::storedPrototype):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36316 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 577565e6
2008-09-10 Maciej Stachowiak <mjs@apple.com>
Reviewed by Oliver.
- enable polymorphic inline caching of properties of primitives
1.012x speedup on SunSpider.
We create special structure IDs for JSString and
JSNumberCell. Unlike normal structure IDs, these cannot hold the
true prototype. Due to JS autoboxing semantics, the prototype used
when looking up string or number properties depends on the lexical
global object of the call site, not the creation site. Thus we
enable StructureIDs to handle this quirk for primitives.
Everything else should be straightforward.
* VM/CTI.cpp:
(JSC::CTI::privateCompileGetByIdProto):
(JSC::CTI::privateCompileGetByIdChain):
* VM/CTI.h:
(JSC::CTI::compileGetByIdProto):
(JSC::CTI::compileGetByIdChain):
* VM/JSPropertyNameIterator.h:
(JSC::JSPropertyNameIterator::JSPropertyNameIterator):
* VM/Machine.cpp:
(JSC::Machine::Machine):
(JSC::cachePrototypeChain):
(JSC::Machine::tryCachePutByID):
(JSC::Machine::tryCacheGetByID):
(JSC::Machine::privateExecute):
(JSC::Machine::tryCTICachePutByID):
(JSC::Machine::tryCTICacheGetByID):
* kjs/GetterSetter.h:
(JSC::GetterSetter::GetterSetter):
* kjs/JSCell.h:
* kjs/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* kjs/JSGlobalData.h:
* kjs/JSGlobalObject.h:
(JSC::StructureID::prototypeForLookup):
* kjs/JSNumberCell.h:
(JSC::JSNumberCell::JSNumberCell):
(JSC::jsNumberCell):
* kjs/JSObject.h:
(JSC::JSObject::prototype):
* kjs/JSString.cpp:
(JSC::jsString):
(JSC::jsSubstring):
(JSC::jsOwnedString):
* kjs/JSString.h:
(JSC::JSString::JSString):
(JSC::JSString::):
(JSC::jsSingleCharacterString):
(JSC::jsSingleCharacterSubstring):
(JSC::jsNontrivialString):
* kjs/SmallStrings.cpp:
(JSC::SmallStrings::createEmptyString):
(JSC::SmallStrings::createSingleCharacterString):
* kjs/StructureID.cpp:
(JSC::StructureID::StructureID):
(JSC::StructureID::addPropertyTransition):
(JSC::StructureID::getterSetterTransition):
(JSC::StructureIDChain::StructureIDChain):
* kjs/StructureID.h:
(JSC::StructureID::create):
(JSC::StructureID::storedPrototype):
2008-09-09 Joerg Bornemann <joerg.bornemann@trolltech.com>
Reviewed by Sam Weinig.
......
......@@ -1672,11 +1672,11 @@ void* CTI::privateCompileGetByIdSelf(StructureID* structureID, size_t cachedOffs
return code;
}
void* CTI::privateCompileGetByIdProto(StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
void* CTI::privateCompileGetByIdProto(ExecState* exec, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
{
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
JSObject* protoObject = static_cast<JSObject*>(structureID->prototype());
JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
OwnArrayPtr<JSValue*>* protoPropertyStorage = &protoObject->m_propertyStorage;
m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
......@@ -1708,7 +1708,7 @@ void* CTI::privateCompileGetByIdProto(StructureID* structureID, StructureID* pro
return code;
}
void* CTI::privateCompileGetByIdChain(StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
void* CTI::privateCompileGetByIdChain(ExecState* exec, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
{
ASSERT(count);
......@@ -1724,7 +1724,7 @@ void* CTI::privateCompileGetByIdChain(StructureID* structureID, StructureIDChain
RefPtr<StructureID>* chainEntries = chain->head();
JSCell* protoObject = 0;
for (unsigned i = 0; i<count; ++i) {
protoObject = static_cast<JSCell*>(currStructureID->prototype());
protoObject = static_cast<JSCell*>(currStructureID->prototypeForLookup(exec));
currStructureID = chainEntries[i].get();
// Check the prototype object's StructureID had not changed.
......
......@@ -245,13 +245,13 @@ namespace JSC {
static void* compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
{
CTI cti(machine, exec, codeBlock);
return cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset);
return cti.privateCompileGetByIdProto(exec, structureID, prototypeStructureID, cachedOffset);
}
static void* compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
{
CTI cti(machine, exec, codeBlock);
return cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset);
return cti.privateCompileGetByIdChain(exec, structureID, chain, count, cachedOffset);
}
static void* compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset)
......@@ -288,8 +288,8 @@ namespace JSC {
void privateCompileSlowCases();
void privateCompile();
void* privateCompileGetByIdSelf(StructureID*, size_t cachedOffset);
void* privateCompileGetByIdProto(StructureID*, StructureID* prototypeStructureID, size_t cachedOffset);
void* privateCompileGetByIdChain(StructureID*, StructureIDChain*, size_t count, size_t cachedOffset);
void* privateCompileGetByIdProto(ExecState*, StructureID*, StructureID* prototypeStructureID, size_t cachedOffset);
void* privateCompileGetByIdChain(ExecState*, StructureID*, StructureIDChain*, size_t count, size_t cachedOffset);
void* privateCompilePutByIdReplace(StructureID*, size_t cachedOffset);
void* privateArrayLengthTrampoline();
void* privateStringLengthTrampoline();
......
......@@ -66,7 +66,8 @@ namespace JSC {
};
inline JSPropertyNameIterator::JSPropertyNameIterator(JSObject* object, Identifier* propertyNames, size_t numProperties)
: m_object(object)
: JSCell(0)
, m_object(object)
, m_propertyNames(propertyNames)
, m_position(propertyNames)
, m_end(propertyNames + numProperties)
......
......@@ -544,7 +544,7 @@ Machine::Machine()
m_jsArrayVptr = jsArray->vptr();
static_cast<JSCell*>(jsArray)->~JSCell();
JSString* jsString = new (storage) JSString("");
JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
m_jsStringVptr = jsString->vptr();
static_cast<JSCell*>(jsString)->~JSCell();
......@@ -1105,9 +1105,9 @@ static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBl
return scopeChain->push(scope);
}
StructureIDChain* cachePrototypeChain(StructureID* structureID)
static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
{
RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototype())->structureID());
RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototypeForLookup(exec))->structureID());
structureID->setCachedPrototypeChain(chain.release());
return structureID->cachedPrototypeChain();
}
......@@ -1136,12 +1136,6 @@ NEVER_INLINE void Machine::tryCachePutByID(CodeBlock* codeBlock, Instruction* vP
JSCell* baseCell = static_cast<JSCell*>(baseValue);
StructureID* structureID = baseCell->structureID();
// FIXME: Remove this !structureID check once all objects have StructureIDs.
if (!structureID) {
vPC[0] = getOpcode(op_put_by_id_generic);
return;
}
if (structureID->isDictionary()) {
vPC[0] = getOpcode(op_put_by_id_generic);
return;
......@@ -1210,12 +1204,6 @@ NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock
StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
// FIXME: Remove this !structureID check once all JSCells have StructureIDs.
if (!structureID) {
vPC[0] = getOpcode(op_get_by_id_generic);
return;
}
if (structureID->isDictionary()) {
vPC[0] = getOpcode(op_get_by_id_generic);
return;
......@@ -1245,7 +1233,7 @@ NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock
return;
}
if (slot.slotBase() == structureID->prototype()) {
if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
ASSERT(slot.slotBase()->isObject());
JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
......@@ -1269,7 +1257,7 @@ NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock
size_t count = 0;
JSObject* o = static_cast<JSObject*>(baseValue);
while (slot.slotBase() != o) {
JSValue* v = o->structureID()->prototype();
JSValue* v = o->structureID()->prototypeForLookup(exec);
// If we didn't find base in baseValue's prototype chain, then baseValue
// must be a proxy for another object.
......@@ -1293,7 +1281,7 @@ NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock
StructureIDChain* chain = structureID->cachedPrototypeChain();
if (!chain)
chain = cachePrototypeChain(structureID);
chain = cachePrototypeChain(exec, structureID);
vPC[0] = getOpcode(op_get_by_id_chain);
vPC[4] = structureID;
......@@ -2264,8 +2252,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
StructureID* structureID = vPC[4].u.structureID;
if (LIKELY(baseCell->structureID() == structureID)) {
ASSERT(structureID->prototype()->isObject());
JSObject* protoObject = static_cast<JSObject*>(structureID->prototype());
ASSERT(structureID->prototypeForLookup(exec)->isObject());
JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
StructureID* protoStructureID = vPC[5].u.structureID;
if (LIKELY(protoObject->structureID() == protoStructureID)) {
......@@ -2305,7 +2293,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
while (1) {
ASSERT(baseCell->isObject());
JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototype());
JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototypeForLookup(exec));
if (UNLIKELY(baseObject->structureID() != (*it).get()))
break;
......@@ -2337,6 +2325,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
int property = vPC[3].u.operand;
Identifier& ident = codeBlock->identifiers[property];
JSValue* baseValue = r[base].jsValue(exec);
PropertySlot slot(baseValue);
JSValue* result = baseValue->get(exec, ident, slot);
......@@ -3549,12 +3538,6 @@ NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBl
JSCell* baseCell = static_cast<JSCell*>(baseValue);
StructureID* structureID = baseCell->structureID();
// FIXME: Remove this !structureID check once all objects have StructureIDs.
if (!structureID) {
ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
return;
}
if (structureID->isDictionary()) {
ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
return;
......@@ -3625,12 +3608,6 @@ NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBl
JSCell* baseCell = static_cast<JSCell*>(baseValue);
StructureID* structureID = baseCell->structureID();
// FIXME: Remove this !structureID check once all JSCells have StructureIDs.
if (!structureID) {
ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
return;
}
if (structureID->isDictionary()) {
ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
return;
......@@ -3655,7 +3632,7 @@ NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBl
return;
}
if (slot.slotBase() == structureID->prototype()) {
if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
ASSERT(slot.slotBase()->isObject());
JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
......@@ -3681,7 +3658,7 @@ NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBl
size_t count = 0;
JSObject* o = static_cast<JSObject*>(baseValue);
while (slot.slotBase() != o) {
JSValue* v = o->structureID()->prototype();
JSValue* v = o->structureID()->prototypeForLookup(exec);
// If we didn't find slotBase in baseValue's prototype chain, then baseValue
// must be a proxy for another object.
......@@ -3706,7 +3683,7 @@ NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBl
StructureIDChain* chain = structureID->cachedPrototypeChain();
if (!chain)
chain = cachePrototypeChain(structureID);
chain = cachePrototypeChain(exec, structureID);
vPC[0] = getOpcode(op_get_by_id_chain);
vPC[4] = structureID;
......
......@@ -34,7 +34,8 @@ namespace JSC {
class GetterSetter : public JSCell {
public:
GetterSetter()
: m_getter(0)
: JSCell(0)
, m_getter(0)
, m_setter(0)
{
}
......
......@@ -40,7 +40,6 @@ namespace JSC {
friend class Machine;
friend class CTI;
private:
JSCell();
JSCell(StructureID*);
virtual ~JSCell();
......@@ -108,11 +107,6 @@ namespace JSC {
StructureID* m_structureID;
};
inline JSCell::JSCell()
: m_structureID(0)
{
}
inline JSCell::JSCell(StructureID* structureID)
: m_structureID(structureID)
{
......
......@@ -77,6 +77,8 @@ JSGlobalData::JSGlobalData(bool isShared)
, stringTable(&JSC::stringTable)
#endif
, nullProtoStructureID(StructureID::create(jsNull()))
, stringStructureID(StructureID::create(jsNull(), StringType))
, numberStructureID(StructureID::create(jsNull(), NumberType))
, identifierTable(createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
, emptyList(new ArgList)
......
......@@ -74,6 +74,8 @@ namespace JSC {
const HashTable* stringTable;
RefPtr<StructureID> nullProtoStructureID;
RefPtr<StructureID> stringStructureID;
RefPtr<StructureID> numberStructureID;
IdentifierTable* identifierTable;
CommonIdentifiers* propertyNames;
......
......@@ -24,6 +24,8 @@
#include "JSGlobalData.h"
#include "JSVariableObject.h"
#include "NumberPrototype.h"
#include "StringPrototype.h"
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
......@@ -293,6 +295,17 @@ namespace JSC {
return globalObject;
}
inline JSValue* StructureID::prototypeForLookup(ExecState* exec) {
if (m_type == ObjectType)
return m_prototype;
if (m_type == StringType)
return exec->lexicalGlobalObject()->stringPrototype();
ASSERT(m_type == NumberType);
return exec->lexicalGlobalObject()->numberPrototype();
}
} // namespace JSC
#endif // JSGlobalObject_h
......@@ -70,8 +70,9 @@ namespace JSC {
}
private:
JSNumberCell(double value)
: m_value(value)
JSNumberCell(ExecState* exec, double value)
: JSCell(exec->globalData().numberStructureID.get())
, m_value(value)
{
}
......@@ -89,7 +90,7 @@ namespace JSC {
// inlining it may not always be a win.
inline JSValue* jsNumberCell(ExecState* exec, double d)
{
return new (exec) JSNumberCell(d);
return new (exec) JSNumberCell(exec, d);
}
inline JSValue* jsNaN(ExecState* exec)
......
......@@ -213,7 +213,7 @@ inline JSObject::~JSObject()
inline JSValue* JSObject::prototype() const
{
return m_structureID->prototype();
return m_structureID->storedPrototype();
}
inline void JSObject::setPrototype(JSValue* prototype)
......
......@@ -125,7 +125,7 @@ JSString* jsString(ExecState* exec, const UString& s)
if (c <= 0xFF)
return exec->globalData().smallStrings.singleCharacterString(exec, c);
}
return new (exec) JSString(s);
return new (exec) JSString(exec, s);
}
JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length)
......@@ -140,7 +140,7 @@ JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsign
if (c <= 0xFF)
return exec->globalData().smallStrings.singleCharacterString(exec, c);
}
return new (exec) JSString(UString::Rep::create(s.rep(), offset, length));
return new (exec) JSString(exec, UString::Rep::create(s.rep(), offset, length));
}
JSString* jsOwnedString(ExecState* exec, const UString& s)
......@@ -153,7 +153,7 @@ JSString* jsOwnedString(ExecState* exec, const UString& s)
if (c <= 0xFF)
return exec->globalData().smallStrings.singleCharacterString(exec, c);
}
return new (exec) JSString(s, JSString::HasOtherOwner);
return new (exec) JSString(exec, s, JSString::HasOtherOwner);
}
} // namespace JSC
......@@ -52,21 +52,25 @@ namespace JSC {
class JSString : public JSCell {
friend class CTI;
friend class Machine;
public:
JSString(const UString& value)
: m_value(value)
JSString(ExecState* exec, const UString& value)
: JSCell(exec->globalData().stringStructureID.get())
, m_value(value)
{
Heap::heap(this)->reportExtraMemoryCost(value.cost());
}
enum HasOtherOwnerType { HasOtherOwner };
JSString(const UString& value, HasOtherOwnerType)
: m_value(value)
JSString(ExecState* exec, const UString& value, HasOtherOwnerType)
: JSCell(exec->globalData().stringStructureID.get())
, m_value(value)
{
}
JSString(PassRefPtr<UString::Rep> value, HasOtherOwnerType)
: m_value(value)
JSString(ExecState* exec, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
: JSCell(exec->globalData().stringStructureID.get())
, m_value(value)
{
}
......@@ -79,6 +83,11 @@ namespace JSC {
JSString* getIndex(ExecState*, unsigned);
private:
enum VPtrStealingHackType { VPtrStealingHack };
JSString(VPtrStealingHackType)
: JSCell(0)
{
}
virtual bool isString() const;
virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType) const;
......@@ -108,7 +117,7 @@ namespace JSC {
{
if (c <= 0xFF)
return exec->globalData().smallStrings.singleCharacterString(exec, c);
return new (exec) JSString(UString(&c, 1));
return new (exec) JSString(exec, UString(&c, 1));
}
inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
......@@ -117,7 +126,7 @@ namespace JSC {
UChar c = s.data()[offset];
if (c <= 0xFF)
return exec->globalData().smallStrings.singleCharacterString(exec, c);
return new (exec) JSString(UString::Rep::create(s.rep(), offset, 1));
return new (exec) JSString(exec, UString::Rep::create(s.rep(), offset, 1));
}
inline JSString* jsNontrivialString(ExecState* exec, const char* s)
......@@ -125,13 +134,13 @@ namespace JSC {
ASSERT(s);
ASSERT(s[0]);
ASSERT(s[1]);
return new (exec) JSString(s);
return new (exec) JSString(exec, s);
}
inline JSString* jsNontrivialString(ExecState* exec, const UString& s)
{
ASSERT(s.size() > 1);
return new (exec) JSString(s);
return new (exec) JSString(exec, s);
}
inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
......
......@@ -90,7 +90,7 @@ void SmallStrings::mark()
void SmallStrings::createEmptyString(ExecState* exec)
{
ASSERT(!m_emptyString);
m_emptyString = new (exec) JSString("", JSString::HasOtherOwner);
m_emptyString = new (exec) JSString(exec, "", JSString::HasOtherOwner);
}
void SmallStrings::createSingleCharacterString(ExecState* exec, unsigned char character)
......@@ -98,7 +98,7 @@ void SmallStrings::createSingleCharacterString(ExecState* exec, unsigned char ch
if (!m_storage)
m_storage.set(new SmallStringsStorage);
ASSERT(!m_singleCharacterStrings[character]);
m_singleCharacterStrings[character] = new (exec) JSString(m_storage->rep(character), JSString::HasOtherOwner);
m_singleCharacterStrings[character] = new (exec) JSString(exec, m_storage->rep(character), JSString::HasOtherOwner);
}
UString::Rep* SmallStrings::singleCharacterStringRep(unsigned char character)
......
......@@ -34,8 +34,9 @@ using namespace std;
namespace JSC {
StructureID::StructureID(JSValue* prototype)
StructureID::StructureID(JSValue* prototype, JSType type)
: m_isDictionary(false)
, m_type(type)
, m_prototype(prototype)
, m_cachedPrototypeChain(0)
, m_previous(0)
......@@ -49,6 +50,7 @@ StructureID::StructureID(JSValue* prototype)
PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot& slot, PropertyStorage& propertyStorage)
{
ASSERT(!structureID->m_isDictionary);
ASSERT(structureID->m_type == ObjectType);
if (StructureID* existingTransition = structureID->m_transitionTable.get(make_pair(propertyName.ustring().rep(), attributes))) {
if (structureID->m_propertyMap.size() != existingTransition->m_propertyMap.size())
......@@ -113,7 +115,7 @@ PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* stru
PassRefPtr<StructureID> StructureID::getterSetterTransition(StructureID* structureID)
{
RefPtr<StructureID> transition = create(structureID->prototype());
RefPtr<StructureID> transition = create(structureID->storedPrototype());
transition->m_transitionCount = structureID->m_transitionCount + 1;
transition->m_propertyMap = structureID->m_propertyMap;
return transition.release();
......@@ -132,9 +134,9 @@ StructureIDChain::StructureIDChain(StructureID* structureID)
size_t size = 1;
StructureID* tmp = structureID;
while (!tmp->prototype()->isNull()) {
while (!tmp->storedPrototype()->isNull()) {
++size;
tmp = static_cast<JSCell*>(tmp->prototype())->structureID();
tmp = static_cast<JSCell*>(tmp->storedPrototype())->structureID();
}
m_vector.set(new RefPtr<StructureID>[size]);
......@@ -142,7 +144,7 @@ StructureIDChain::StructureIDChain(StructureID* structureID)
size_t i;
for (i = 0; i < size - 1; ++i) {
m_vector[i] = structureID;
structureID = static_cast<JSObject*>(structureID->prototype())->structureID();
structureID = static_cast<JSObject*>(structureID->storedPrototype())->structureID();
}
m_vector[i] = structureID;
}
......
......@@ -26,6 +26,7 @@
#ifndef StructureID_h
#define StructureID_h
#include "JSType.h"
#include "JSValue.h"
#include "PropertyMap.h"
#include "ustring.h"
......@@ -71,9 +72,9 @@ namespace JSC {
class StructureID : public RefCounted<StructureID> {
public:
static PassRefPtr<StructureID> create(JSValue* prototype)
static PassRefPtr<StructureID> create(JSValue* prototype, JSType type = ObjectType)
{
return adoptRef(new StructureID(prototype));
return adoptRef(new StructureID(prototype, type));
}
static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype);
......@@ -92,8 +93,9 @@ namespace JSC {
bool isDictionary() const { return m_isDictionary; }
JSValue* prototype() const { return m_prototype; }
JSValue* storedPrototype() const { return m_prototype; }
JSValue* prototypeForLookup(ExecState*);
void setCachedPrototypeChain(PassRefPtr<StructureIDChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); }
......@@ -104,11 +106,12 @@ namespace JSC {
typedef std::pair<RefPtr<UString::Rep>, unsigned> TransitionTableKey;
typedef HashMap<TransitionTableKey, StructureID*, TransitionTableHash, TransitionTableHashTraits> TransitionTable;
StructureID(JSValue* prototype);
StructureID(JSValue* prototype, JSType);
static const size_t s_maxTransitionLength = 64;
bool m_isDictionary;
JSType m_type;
JSValue* m_prototype;
RefPtr<StructureIDChain> m_cachedPrototypeChain;
......
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