2008-09-10 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Sep 2008 08:42:43 +0000 (08:42 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Sep 2008 08:42:43 +0000 (08:42 +0000)
        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

17 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/JSPropertyNameIterator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/GetterSetter.h
JavaScriptCore/kjs/JSCell.h
JavaScriptCore/kjs/JSGlobalData.cpp
JavaScriptCore/kjs/JSGlobalData.h
JavaScriptCore/kjs/JSGlobalObject.h
JavaScriptCore/kjs/JSNumberCell.h
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/JSString.cpp
JavaScriptCore/kjs/JSString.h
JavaScriptCore/kjs/SmallStrings.cpp
JavaScriptCore/kjs/StructureID.cpp
JavaScriptCore/kjs/StructureID.h

index aa98a4fa1ce0b3b93763ae0ae81b8455b430442c..a43dcb2ea98a606245ecc219253d08c45d6cc4e4 100644 (file)
@@ -1,3 +1,71 @@
+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.
index 2a9c9d9464c1f084cee924326f338d8f2ca125d3..cab68188dd555dff9e29f8c548449e1b560f7b9f 100644 (file)
@@ -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.
index c188a30f6f5554ae1bb6fb1ca1434a2f405a2984..bcb5db32044ab698f38f9f8d6e2cee87b5471614 100644 (file)
@@ -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();
index ea28c3f9e6341d1ff13fb45062a3dc2cd4ef9d17..716b5442f1fb0a670739461fa038393bb60819bb 100644 (file)
@@ -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)
index 80011047de7b42a296f6be38902d5f8030a607a4..3fb01523afeab974eb96aa048410b0827a38a3f8 100644 (file)
@@ -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;
index abdd7c3d6a3c7948c3788fd18d75df2ba7f0688a..e8e6ff6bc58712f994223aa2449d93b4d0db9c40 100644 (file)
@@ -34,7 +34,8 @@ namespace JSC {
     class GetterSetter : public JSCell {
     public:
         GetterSetter()
-            : m_getter(0)
+            : JSCell(0)
+            , m_getter(0)
             , m_setter(0)
         {
         }
index 409e6d82cef5c9eb9fa811d333737a62daf24c72..03ad11a24584e010f268b3c2d1f1a625e56d9437 100644 (file)
@@ -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)
     {
index 78614e6fdeccee778fdb0f67be53ea360844cd52..1c40c2579eeb4069ffdd52eb26afbc4a33d9919e 100644 (file)
@@ -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)
index 33f0ac0d04a3e976732b9c7b20df7d39b99684f3..4e818b8b6a92a1487d0fef1a4139dc3fd75940c0 100644 (file)
@@ -74,6 +74,8 @@ namespace JSC {
         const HashTable* stringTable;
         
         RefPtr<StructureID> nullProtoStructureID;
+        RefPtr<StructureID> stringStructureID;
+        RefPtr<StructureID> numberStructureID;
 
         IdentifierTable* identifierTable;
         CommonIdentifiers* propertyNames;
index 095e0a45fec6311398c7925f6ab8e2f70e8f9335..1e2589eb37bf9e60ddb5963a80fcb1c0ff4f303a 100644 (file)
@@ -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
index 0c4351de3340464ef782808b965df7e5571e09b8..7e4878a1c130d454bb706c6c9fc9b9188e8df9b5 100644 (file)
@@ -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)
index b194e61ff399faec88c11476561c65e3fa3c6542..58ff583c9f0334b7e9b78173a988385c9b57412c 100644 (file)
@@ -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)
index d6124b62ef75b9767d9c0d7411e8e2714023e462..2185371b32350d4e3c16e61f9b58cb976c1477cd 100644 (file)
@@ -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
index 235c86bb3fea654c041ace2d36731460c79bf7be..443994f505a54b6dc1b60f52c381a3ab8cc844fb 100644 (file)
@@ -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)
index 0c36a2d0434b1bf4009d675f5421992d85a5524a..668ce9ae4949c2f4cf4f0ea54eeddb2bea25803e 100644 (file)
@@ -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)
index 80eef36cb3e922d710117431ee982945b8195e5b..061d6626a07ce41a6f08e32444725b6cecef450f 100644 (file)
@@ -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;
 }
index e2a4ccadd71b11aec5084f13f6f2885c5b7199c8..67ab4b448b46db2c775550f6810f5c350a6a7342 100644 (file)
@@ -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;