JavaScriptCore:
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Sep 2008 02:31:45 +0000 (02:31 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Sep 2008 02:31:45 +0000 (02:31 +0000)
2008-09-02  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Sam Weinig.

        Implemented the rest of Darin's review comments for the 09-01 inline
        caching patch.

        SunSpider says 0.5% faster, but that seems like noise.

        * JavaScriptCore.xcodeproj/project.pbxproj: Put PutPropertySlot into
        its own file, and added BatchedTransitionOptimizer.

        * VM/CodeBlock.cpp:
        (KJS::CodeBlock::~CodeBlock): Use array indexing instead of a pointer
        iterator.

        * VM/CodeGenerator.cpp:
        (KJS::CodeGenerator::CodeGenerator): Used BatchedTransitionOptimizer to
        make batched put and remove for declared variables fast, without forever
        pessimizing the global object. Removed the old getDirect/removeDirect hack
        that tried to do the same in a more limited way.

        * VM/CodeGenerator.h: Moved IdentifierRepHash to the KJS namespace since
        it doesn't specialize anything in WTF.

        * VM/Machine.cpp:
        (KJS::Machine::Machine): Nixed the DummyConstruct tag because it was
        confusingly named.

        (KJS::Machine::execute):  Used BatchedTransitionOptimizer, as above. Fixed
        up some comments.

        (KJS::cachePrototypeChain): Cast to JSObject*, since it's more specific.

        (KJS::Machine::tryCachePutByID): Use isNull() instead of comparing to
        jsNull(), since isNull() leaves more options open for the future.
        (KJS::Machine::tryCacheGetByID): ditto
        (KJS::Machine::privateExecute): ditto

        * VM/SamplingTool.cpp:
        (KJS::SamplingTool::dump): Use C++-style cast, to match our style
        guidelines.

        * kjs/BatchedTransitionOptimizer.h: Added. New class that allows host
        code to add a batch of properties to an object in an efficient way.

        * kjs/JSActivation.cpp: Use isNull(), as above.

        * kjs/JSArray.cpp: Get rid of DummyConstruct tag, as above.
        * kjs/JSArray.h:

        * kjs/JSGlobalData.cpp: Nixed two unused StructureIDs.
        * kjs/JSGlobalData.h:

        * kjs/JSImmediate.cpp: Use isNull(), as above.

        * kjs/JSObject.cpp:
        (KJS::JSObject::mark): Moved mark tracing code elsewhere, to make this
        function more readable.

        (KJS::JSObject::put): Use isNull(), as above.

        (KJS::JSObject::createInheritorID): Return a raw pointer, since the
        object is owned by a data member, not necessarily the caller.
        * kjs/JSObject.h:

        * kjs/JSString.cpp: Use isNull(), as above.

        * kjs/PropertyMap.h: Updated to use PropertySlot::invalidOffset.

        * kjs/PropertySlot.h: Changed KJS_INVALID_OFFSET to WTF::notFound
        because C macros are so 80's.

        * kjs/PutPropertySlot.h: Added. Split out of PropertySlot.h. Also renamed
        PutPropertySlot::SlotType to PutPropertySlot::Type, and slotBase to base,
        since "slot" was redundant.

        * kjs/StructureID.cpp: Added a new transition *away* from dictionary
        status, to support BatchedTransitionOptimizer.

        (KJS::StructureIDChain::StructureIDChain): No need to store m_size as
        a data member, so keep it in a local, which might be faster.
        * kjs/StructureID.h:

        * kjs/SymbolTable.h: Moved IdentifierRepHash to KJS namespace, as above.
        * kjs/ustring.h:

JavaScriptGlue:

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

        Reviewed by Sam Weinig.

        Implemented the rest of Darin's review comments for the 09-01 inline
        caching patch.

        * ForwardingHeaders/kjs/PutPropertySlot.h: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@36032 268f45cc-cd09-0410-ab3c-d52691b4dbfc

29 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/SamplingTool.cpp
JavaScriptCore/kjs/BatchedTransitionOptimizer.h [new file with mode: 0644]
JavaScriptCore/kjs/JSActivation.cpp
JavaScriptCore/kjs/JSArray.cpp
JavaScriptCore/kjs/JSArray.h
JavaScriptCore/kjs/JSGlobalData.cpp
JavaScriptCore/kjs/JSGlobalData.h
JavaScriptCore/kjs/JSImmediate.cpp
JavaScriptCore/kjs/JSObject.cpp
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/JSString.cpp
JavaScriptCore/kjs/PropertyMap.cpp
JavaScriptCore/kjs/PropertyMap.h
JavaScriptCore/kjs/PropertySlot.h
JavaScriptCore/kjs/PutPropertySlot.h [new file with mode: 0644]
JavaScriptCore/kjs/StructureID.cpp
JavaScriptCore/kjs/StructureID.h
JavaScriptCore/kjs/SymbolTable.h
JavaScriptCore/kjs/ustring.h
JavaScriptGlue/ChangeLog
JavaScriptGlue/ForwardingHeaders/kjs/PutPropertySlot.h [new file with mode: 0644]
JavaScriptGlue/ForwardingHeaders/wtf/NotFound.h [new file with mode: 0644]

index dfad501..218473c 100644 (file)
@@ -1,3 +1,90 @@
+2008-09-02  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Sam Weinig.
+        
+        Implemented the rest of Darin's review comments for the 09-01 inline
+        caching patch.
+        
+        SunSpider says 0.5% faster, but that seems like noise.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj: Put PutPropertySlot into
+        its own file, and added BatchedTransitionOptimizer.
+
+        * VM/CodeBlock.cpp:
+        (KJS::CodeBlock::~CodeBlock): Use array indexing instead of a pointer
+        iterator.
+
+        * VM/CodeGenerator.cpp:
+        (KJS::CodeGenerator::CodeGenerator): Used BatchedTransitionOptimizer to
+        make batched put and remove for declared variables fast, without forever
+        pessimizing the global object. Removed the old getDirect/removeDirect hack
+        that tried to do the same in a more limited way.
+
+        * VM/CodeGenerator.h: Moved IdentifierRepHash to the KJS namespace since
+        it doesn't specialize anything in WTF.
+
+        * VM/Machine.cpp:
+        (KJS::Machine::Machine): Nixed the DummyConstruct tag because it was
+        confusingly named.
+
+        (KJS::Machine::execute):  Used BatchedTransitionOptimizer, as above. Fixed
+        up some comments.
+
+        (KJS::cachePrototypeChain): Cast to JSObject*, since it's more specific.
+
+        (KJS::Machine::tryCachePutByID): Use isNull() instead of comparing to
+        jsNull(), since isNull() leaves more options open for the future.
+        (KJS::Machine::tryCacheGetByID): ditto
+        (KJS::Machine::privateExecute): ditto
+
+        * VM/SamplingTool.cpp:
+        (KJS::SamplingTool::dump): Use C++-style cast, to match our style
+        guidelines.
+
+        * kjs/BatchedTransitionOptimizer.h: Added. New class that allows host
+        code to add a batch of properties to an object in an efficient way.
+
+        * kjs/JSActivation.cpp: Use isNull(), as above.
+
+        * kjs/JSArray.cpp: Get rid of DummyConstruct tag, as above.
+        * kjs/JSArray.h:
+
+        * kjs/JSGlobalData.cpp: Nixed two unused StructureIDs.
+        * kjs/JSGlobalData.h:
+
+        * kjs/JSImmediate.cpp: Use isNull(), as above.
+
+        * kjs/JSObject.cpp:
+        (KJS::JSObject::mark): Moved mark tracing code elsewhere, to make this
+        function more readable.
+
+        (KJS::JSObject::put): Use isNull(), as above.
+
+        (KJS::JSObject::createInheritorID): Return a raw pointer, since the
+        object is owned by a data member, not necessarily the caller.
+        * kjs/JSObject.h:
+
+        * kjs/JSString.cpp: Use isNull(), as above.
+
+        * kjs/PropertyMap.h: Updated to use PropertySlot::invalidOffset.
+
+        * kjs/PropertySlot.h: Changed KJS_INVALID_OFFSET to WTF::notFound
+        because C macros are so 80's.
+
+        * kjs/PutPropertySlot.h: Added. Split out of PropertySlot.h. Also renamed
+        PutPropertySlot::SlotType to PutPropertySlot::Type, and slotBase to base,
+        since "slot" was redundant.
+
+        * kjs/StructureID.cpp: Added a new transition *away* from dictionary
+        status, to support BatchedTransitionOptimizer.
+
+        (KJS::StructureIDChain::StructureIDChain): No need to store m_size as
+        a data member, so keep it in a local, which might be faster.
+        * kjs/StructureID.h:
+
+        * kjs/SymbolTable.h: Moved IdentifierRepHash to KJS namespace, as above.
+        * kjs/ustring.h:
+
 2008-09-02  Adam Roben  <aroben@apple.com>
 
         Windows build fixes
index 0bdfe2d..906c183 100644 (file)
@@ -108,6 +108,7 @@ __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierERb
 __ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjbPNS_8JSObjectERNS_15PutPropertySlotE
 __ZN3KJS11PropertyMapD1Ev
 __ZN3KJS11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierE
+__ZN3KJS11StructureID24fromDictionaryTransitionEPS0_
 __ZN3KJS11StructureID25changePrototypeTransitionEPS0_PNS_7JSValueE
 __ZN3KJS11StructureIDD1Ev
 __ZN3KJS12DateInstance4infoE
index 752d153..3d7b53f 100644 (file)
@@ -54,6 +54,8 @@
                1440F8AF0A508D200005F061 /* JSCallbackConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440F8AD0A508D200005F061 /* JSCallbackConstructor.cpp */; };
                1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440FCE20A51E46B0005F061 /* JSClassRef.cpp */; };
                146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */; };
+               147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; };
+               147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B74C0A43032800517CFC /* JSStringRef.cpp */; };
                1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B7E20A43076000517CFC /* JSObjectRef.cpp */; };
                14909A2D0DCAF6CD00B29EB3 /* ExecState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD53F40A3E12D800BAF59C /* ExecState.cpp */; };
                146AAB2A0B66A84900E55F16 /* JSStringRefCF.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSStringRefCF.h; sourceTree = "<group>"; };
                146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringRefCF.cpp; sourceTree = "<group>"; };
                14760863099C633800437128 /* JSImmediate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSImmediate.cpp; sourceTree = "<group>"; };
+               147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BatchedTransitionOptimizer.h; sourceTree = "<group>"; };
+               147B84620E6DE6B1004775A4 /* PutPropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutPropertySlot.h; sourceTree = "<group>"; };
                1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebuggerCallFrame.h; path = kjs/DebuggerCallFrame.h; sourceTree = "<group>"; };
                1482B6EA0A4300B300517CFC /* JSValueRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueRef.h; sourceTree = "<group>"; };
                1482B74B0A43032800517CFC /* JSStringRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringRef.h; sourceTree = "<group>"; };
                                5D53726E0E1C54880021E549 /* Tracing.h */,
                                F692A8850255597D01FF60F7 /* ustring.cpp */,
                                F692A8860255597D01FF60F7 /* ustring.h */,
+                               147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */,
+                               147B84620E6DE6B1004775A4 /* PutPropertySlot.h */,
                        );
                        path = kjs;
                        sourceTree = "<group>";
                                9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */,
                                933040040E6A749400786E6A /* SmallStrings.h in Headers */,
                                BCDE3AB80E6C82F5001453A7 /* StructureID.h in Headers */,
+                               147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */,
+                               147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 6b319f1..922e557 100644 (file)
@@ -799,9 +799,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
 
 CodeBlock::~CodeBlock()
 {
-    Vector<size_t>::const_iterator end = structureIDInstructions.end();
-    for (Vector<size_t>::const_iterator it = structureIDInstructions.begin(); it != end; ++it)
-        derefStructureIDs(&instructions[*it]);
+    size_t size = structureIDInstructions.size();
+    for (size_t i = 0; i < size; ++i)
+        derefStructureIDs(&instructions[structureIDInstructions[i]]);
 }
 
 void CodeBlock::derefStructureIDs(Instruction* vPC) const
index d7b7afd..2b11ea0 100644 (file)
@@ -30,6 +30,7 @@
 #include "config.h"
 #include "CodeGenerator.h"
 
+#include "BatchedTransitionOptimizer.h"
 #include "JSFunction.h"
 #include "Machine.h"
 #include "ustring.h"
@@ -219,6 +220,8 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
     SymbolTable::iterator end = symbolTable->end();
     for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
         m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
+        
+    BatchedTransitionOptimizer optimizer(globalObject);
 
     bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
     if (canOptimizeNewGlobals) {
@@ -227,8 +230,7 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
 
         for (size_t i = 0; i < functionStack.size(); ++i) {
             FuncDeclNode* funcDecl = functionStack[i].get();
-            if (globalObject->getDirect(funcDecl->m_ident))
-                globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
+            globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
             emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
         }
 
index 4ba6fa9..2a3e62d 100644 (file)
@@ -345,7 +345,7 @@ namespace KJS {
             static const bool needsRef = false;
         };
 
-        typedef HashMap<RefPtr<UString::Rep>, int, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
+        typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
 
         RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
 
@@ -397,7 +397,7 @@ namespace KJS {
         ScopeNode* m_scopeNode;
         CodeBlock* m_codeBlock;
 
-        HashSet<RefPtr<UString::Rep>, WTF::IdentifierRepHash> m_functions;
+        HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions;
         RegisterID m_thisRegister;
         SegmentedVector<RegisterID, 512> m_locals;
         SegmentedVector<RegisterID, 512> m_constants;
index 6d1d609..5463a05 100644 (file)
@@ -30,6 +30,7 @@
 #include "config.h"
 #include "Machine.h"
 
+#include "BatchedTransitionOptimizer.h"
 #include "CodeBlock.h"
 #include "DebuggerCallFrame.h"
 #include "ExceptionHelpers.h"
@@ -539,7 +540,7 @@ Machine::Machine()
     // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
     void* storage = fastMalloc(sizeof(CollectorBlock));
 
-    JSArray* jsArray = new (storage) JSArray(JSArray::DummyConstruct);
+    JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
     m_jsArrayVptr = jsArray->vptr();
     static_cast<JSCell*>(jsArray)->~JSCell();
 
@@ -884,21 +885,27 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
         }
     }
 
-    const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
-    Node::VarStack::const_iterator varStackEnd = varStack.end();
-    for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
-        const Identifier& ident = (*it).first;
-        if (!variableObject->hasProperty(exec, ident)) {
+    { // Scope for BatchedTransitionOptimizer
+
+        BatchedTransitionOptimizer optimizer(variableObject);
+
+        const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
+        Node::VarStack::const_iterator varStackEnd = varStack.end();
+        for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
+            const Identifier& ident = (*it).first;
+            if (!variableObject->hasProperty(exec, ident)) {
+                PutPropertySlot slot;
+                variableObject->put(exec, ident, jsUndefined(), slot);
+            }
+        }
+
+        const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
+        Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
+        for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
             PutPropertySlot slot;
-            variableObject->put(exec, ident, jsUndefined(), slot);
+            variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
         }
-    }
 
-    const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
-    Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
-    for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
-        PutPropertySlot slot;
-        variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
     }
 
     size_t oldSize = m_registerFile.size();
@@ -1096,7 +1103,7 @@ static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBl
 
 StructureIDChain* cachePrototypeChain(StructureID* structureID)
 {
-    RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSCell*>(structureID->prototype())->structureID());
+    RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototype())->structureID());
     structureID->setCachedPrototypeChain(chain.release());
     return structureID->cachedPrototypeChain();
 }
@@ -1152,8 +1159,8 @@ NEVER_INLINE void Machine::tryCachePutByID(CodeBlock* codeBlock, Instruction* vP
 
     // Cache hit: Specialize instruction and ref StructureIDs.
 
-    // If baseCell != slotBase, then baseCell must be a proxy for another object.
-    if (baseCell != slot.slotBase()) {
+    // If baseCell != slot.base(), then baseCell must be a proxy for another object.
+    if (baseCell != slot.base()) {
         vPC[0] = getOpcode(op_put_by_id_generic);
         return;
     }
@@ -1242,7 +1249,7 @@ NEVER_INLINE void Machine::tryCacheGetByID(CodeBlock* codeBlock, Instruction* vP
         baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
         // If we didn't find slotBase in baseCell's prototype chain, then baseCell
         // must be a proxy for another object.
-        if (baseCell == jsNull()) {
+        if (baseCell->isNull()) {
             vPC[0] = getOpcode(op_get_by_id_generic);
             return;
         }
@@ -2203,7 +2210,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
 
            Cached property access: Attempts to get a cached property from the
-           value base's prototype chain. If the cache misses, op_get_by_id_proto
+           value base's prototype chain. If the cache misses, op_get_by_id_chain
            reverts to op_get_by_id.
         */
         int base = vPC[2].u.operand;
@@ -2219,13 +2226,12 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
                 RefPtr<StructureID>* end = it + count;
 
                 while (1) {
-                    baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
-                    if (UNLIKELY(baseCell->structureID() != (*it).get()))
+                    ASSERT(baseCell->isObject());
+                    JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototype());
+                    if (UNLIKELY(baseObject->structureID() != (*it).get()))
                         break;
 
                     if (++it == end) {
-                        ASSERT(baseCell->isObject());
-                        JSObject* baseObject = static_cast<JSObject*>(baseCell);
                         int dst = vPC[1].u.operand;
                         int offset = vPC[7].u.operand;
 
@@ -2265,8 +2271,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
     BEGIN_OPCODE(op_put_by_id) {
         /* put_by_id base(r) property(id) value(r) nop(n) nop(n)
 
-           Sets register value on register base as the property named
-           by identifier property. Base is converted to object first.
+           Generic property access: Sets the property named by identifier
+           property, belonging to register base, to register value.
 
            Unlike many opcodes, this one does not write any output to
            the register file.
@@ -2291,8 +2297,10 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
     BEGIN_OPCODE(op_put_by_id_replace) {
         /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n)
 
-           Sets register value on register base as the property named
-           by identifier property. Base is converted to object first.
+           Cached property access: Attempts to set a pre-existing, cached
+           property named by identifier property, belonging to register base,
+           to register value. If the cache misses, op_put_by_id_replace
+           reverts to op_put_by_id.
 
            Unlike many opcodes, this one does not write any output to
            the register file.
@@ -2324,8 +2332,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
     BEGIN_OPCODE(op_put_by_id_generic) {
         /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n)
 
-           Sets register value on register base as the property named
-           by identifier property. Base is converted to object first.
+           Generic property access: Sets the property named by identifier
+           property, belonging to register base, to register value.
 
            Unlike many opcodes, this one does not write any output to
            the register file.
index e8c022e..0eb0c26 100644 (file)
@@ -266,7 +266,7 @@ void SamplingTool::dump(ExecState* exec)
     printf("Opcodes in order:\n\n");
     for (int i = 0; i < numOpcodeIDs; ++i) {
         long long count = opcodeSampleCounts[i];
-        printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName((OpcodeID)i, 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);    
+        printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName(static_cast<OpcodeID>(i), 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);    
     }
     printf("\n");
     printf("Opcodes by sample count:\n\n");
diff --git a/JavaScriptCore/kjs/BatchedTransitionOptimizer.h b/JavaScriptCore/kjs/BatchedTransitionOptimizer.h
new file mode 100644 (file)
index 0000000..14883bd
--- /dev/null
@@ -0,0 +1,55 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef BatchedTransitionOptimizer_h
+#define BatchedTransitionOptimizer_h
+
+#include <wtf/Noncopyable.h>
+#include "JSObject.h"
+
+namespace KJS {
+
+    class BatchedTransitionOptimizer : Noncopyable {
+    public:
+        BatchedTransitionOptimizer(JSObject* object)
+            : m_object(object)
+        {
+            if (!m_object->structureID()->isDictionary())
+                m_object->setStructureID(StructureID::toDictionaryTransition(m_object->structureID()));
+        }
+
+        ~BatchedTransitionOptimizer()
+        {
+            m_object->setStructureID(StructureID::fromDictionaryTransition(m_object->structureID()));
+        }
+
+    private:
+        JSObject* m_object;
+    };
+
+} // namespace KJS
+
+#endif // BatchedTransitionOptimizer_h
index 23d8e4e..8a73678 100644 (file)
@@ -79,7 +79,7 @@ bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propert
     // We don't call through to JSObject because there's no way to give an 
     // activation object getter properties or a prototype.
     ASSERT(!hasGetterSetterProperties());
-    ASSERT(prototype() == jsNull());
+    ASSERT(prototype()->isNull());
     return false;
 }
 
index 5aa8936..fa994cc 100644 (file)
@@ -125,8 +125,8 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
 
 #endif
 
-JSArray::JSArray(DummyConstructTag)
-    : JSObject(StructureID::create(jsNull()))
+JSArray::JSArray(PassRefPtr<StructureID> structureID)
+    : JSObject(structureID)
 {
     unsigned initialCapacity = 0;
 
index a35cffc..b65092b 100644 (file)
@@ -38,8 +38,7 @@ namespace KJS {
 
     class JSArray : public JSObject {
     public:
-        enum DummyConstructTag { DummyConstruct };
-        JSArray(DummyConstructTag);
+        JSArray(PassRefPtr<StructureID>);
         JSArray(JSObject* prototype, unsigned initialLength);
         JSArray(ExecState* exec, JSObject* prototype, const ArgList& initialValues);
         virtual ~JSArray();
index 491a2d8..57889b0 100644 (file)
@@ -76,8 +76,6 @@ JSGlobalData::JSGlobalData(bool isShared)
     , regExpConstructorTable(&KJS::regExpConstructorTable)
     , stringTable(&KJS::stringTable)
 #endif
-    , stringStructureID(StructureID::create(jsNull()))
-    , numberStructureID(StructureID::create(jsNull()))
     , nullProtoStructureID(StructureID::create(jsNull()))
     , identifierTable(createIdentifierTable())
     , propertyNames(new CommonIdentifiers(this))
index a807013..b8a6a9c 100644 (file)
@@ -73,8 +73,6 @@ namespace KJS {
         const HashTable* regExpConstructorTable;
         const HashTable* stringTable;
         
-        RefPtr<StructureID> stringStructureID;
-        RefPtr<StructureID> numberStructureID;
         RefPtr<StructureID> nullProtoStructureID;
 
         IdentifierTable* identifierTable;
index 8154fe9..9f16129 100644 (file)
@@ -40,7 +40,7 @@ JSObject* JSImmediate::toObject(const JSValue* v, ExecState* exec)
     if (isBoolean(v))
         return constructBooleanFromImmediateBoolean(exec, const_cast<JSValue*>(v));
     
-    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v->isNull());
     exec->setException(exception);
     return new (exec) JSNotAnObject(exec, exception);
 }
@@ -53,7 +53,7 @@ JSObject* JSImmediate::prototype(const JSValue* v, ExecState* exec)
     if (isBoolean(v))
         return exec->lexicalGlobalObject()->booleanPrototype();
 
-    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v->isNull());
     exec->setException(exception);
     return new (exec) JSNotAnObject(exec, exception);
 }
@@ -67,7 +67,7 @@ UString JSImmediate::toString(const JSValue* v)
         return "false";
     if (v == jsBoolean(true))
         return "true";
-    if (v == jsNull())
+    if (v->isNull())
         return "null";
     ASSERT(v == jsUndefined());
     return "undefined";
index dffff27..a106a2c 100644 (file)
 #include <profiler/Profiler.h>
 #include <wtf/Assertions.h>
 
-#define JAVASCRIPT_MARK_TRACING 0
+#define JSOBJECT_MARK_TRACING 0
+
+#if JSOBJECT_MARK_TRACING
+
+#define JSOBJECT_MARK_BEGIN() \
+    static int markStackDepth = 0; \
+    for (int i = 0; i < markStackDepth; i++) \
+        putchar('-'); \
+    printf("%s (%p)\n", className().UTF8String().c_str(), this); \
+    markStackDepth++; \
+
+#define JSOBJECT_MARK_END() \
+    markStackDepth--;
+
+#else // JSOBJECT_MARK_TRACING
+
+#define JSOBJECT_MARK_BEGIN()
+#define JSOBJECT_MARK_END()
+
+#endif // JSOBJECT_MARK_TRACING
 
 namespace KJS {
 
@@ -46,22 +65,13 @@ ASSERT_CLASS_FITS_IN_CELL(JSObject);
 
 void JSObject::mark()
 {
-    JSCell::mark();
-
-#if JAVASCRIPT_MARK_TRACING
-    static int markStackDepth = 0;
-    markStackDepth++;
-    for (int i = 0; i < markStackDepth; i++)
-        putchar('-');
-    printf("%s (%p)\n", className().UTF8String().c_str(), this);
-#endif
+    JSOBJECT_MARK_BEGIN();
 
+    JSCell::mark();
     m_structureID->mark();
     m_propertyMap.mark();
 
-#if JAVASCRIPT_MARK_TRACING
-    markStackDepth--;
-#endif
+    JSOBJECT_MARK_END();
 }
 
 UString JSObject::className() const
@@ -92,7 +102,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
         JSObject* proto = value->getObject();
 
         // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
-        if (!proto && value != jsNull())
+        if (!proto && !value->isNull())
             return;
         
         while (proto) {
@@ -111,7 +121,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
     JSValue* prototype;
     for (JSObject* obj = this; !obj->m_propertyMap.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
         prototype = obj->prototype();
-        if (prototype == jsNull()) {
+        if (prototype->isNull()) {
             putDirect(propertyName, value, 0, true, slot);
             return;
         }
@@ -144,7 +154,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
         }
 
         prototype = obj->prototype();
-        if (prototype == jsNull())
+        if (prototype->isNull())
             break;
     }
 
@@ -477,7 +487,7 @@ void JSObject::removeDirect(const Identifier& propertyName)
 {
     m_propertyMap.remove(propertyName);
     if (!m_structureID->isDictionary()) {
-        RefPtr<StructureID> structureID = StructureID::dictionaryTransition(m_structureID);
+        RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
         setStructureID(structureID.release());
     }
 }
@@ -495,10 +505,10 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue**
         slot.setUndefined();
 }
 
-PassRefPtr<StructureID> JSObject::createInheritorID()
+StructureID* JSObject::createInheritorID()
 {
     m_inheritorID = StructureID::create(this);
-    return m_inheritorID;
+    return m_inheritorID.get();
 }
 
 bool JSObject::isObject() const
index e240d4b..381980d 100644 (file)
@@ -30,6 +30,7 @@
 #include "JSNumberCell.h"
 #include "PropertyMap.h"
 #include "PropertySlot.h"
+#include "PutPropertySlot.h"
 #include "ScopeChain.h"
 #include "StructureID.h"
 
@@ -52,6 +53,8 @@ namespace KJS {
     };
 
     class JSObject : public JSCell {
+        friend class BatchedTransitionOptimizer;
+
     public:
         JSObject(PassRefPtr<StructureID>);
         JSObject(JSObject* prototype);
@@ -64,7 +67,7 @@ namespace KJS {
         JSValue* prototype() const;
         void setPrototype(JSValue* prototype);
         
-        PassRefPtr<StructureID> inheritorID();
+        StructureID* inheritorID();
 
         virtual UString className() const;
 
@@ -152,7 +155,7 @@ namespace KJS {
 
         const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
         void setStructureID(PassRefPtr<StructureID>);
-        PassRefPtr<StructureID> createInheritorID();
+        StructureID* createInheritorID();
 
         PropertyMap m_propertyMap;
         RefPtr<StructureID> m_inheritorID;
@@ -161,11 +164,12 @@ namespace KJS {
   JSObject* constructEmptyObject(ExecState*);
 
 inline JSObject::JSObject(JSObject* prototype)
-    : JSCell(prototype->inheritorID().releaseRef()) // ~JSObject balances this ref()
+    : JSCell(prototype->inheritorID())
 {
     ASSERT(m_structureID);
     ASSERT(this->prototype());
-    ASSERT(this->prototype() == jsNull() || Heap::heap(this) == Heap::heap(this->prototype()));
+    ASSERT(this->prototype()->isNull() || Heap::heap(this) == Heap::heap(this->prototype()));
+    m_structureID->ref(); // ~JSObject balances this ref()
 }
 
 inline JSObject::JSObject(PassRefPtr<StructureID> structureID)
@@ -198,7 +202,7 @@ inline void JSObject::setStructureID(PassRefPtr<StructureID> structureID)
     m_structureID = structureID.releaseRef(); // ~JSObject balances this ref()
 }
 
-inline PassRefPtr<StructureID> JSObject::inheritorID()
+inline StructureID* JSObject::inheritorID()
 {
     if (m_inheritorID)
         return m_inheritorID.get();
index c207923..0b8ce70 100644 (file)
@@ -90,7 +90,7 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam
         return true;
     slot.setBase(this);
     JSObject* object;
-    for (JSValue* prototype = exec->lexicalGlobalObject()->stringPrototype(); prototype != jsNull(); prototype = object->prototype()) {
+    for (JSValue* prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype->isNull(); prototype = object->prototype()) {
         ASSERT(prototype->isObject());
         object = static_cast<JSObject*>(prototype);
         if (object->getOwnPropertySlot(exec, propertyName, slot))
index f1d510e..d6715cc 100644 (file)
@@ -331,7 +331,7 @@ void PropertyMap::put(const Identifier& propertyName, JSValue* value, unsigned a
             m_u.singleEntryValue = value;
             m_singleEntryAttributes = static_cast<short>(attributes);
             checkConsistency();
-            slot.setNewProperty(slotBase, KJS_INVALID_OFFSET);
+            slot.setNewProperty(slotBase, WTF::notFound);
             return;
         }
         if (rep == m_singleEntryKey && !(checkReadOnly && (m_singleEntryAttributes & ReadOnly))) {
index 0ad294a..f45e6bf 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "PropertySlot.h"
 #include "identifier.h"
+#include <wtf/NotFound.h>
 
 namespace KJS {
 
@@ -104,7 +105,7 @@ namespace KJS {
             reinterpret_cast<JSValue**>(m_u.table->entryIndicies)[offset] = v;
         }
 
-        size_t offsetForLocation(JSValue** location) { return m_usingTable ? offsetForTableLocation(location) : KJS_INVALID_OFFSET; }
+        size_t offsetForLocation(JSValue** location) { return m_usingTable ? offsetForTableLocation(location) : WTF::notFound; }
 
         void mark() const;
         void getEnumerablePropertyNames(PropertyNameArray&) const;
index 8070f5e..9a0944f 100644 (file)
@@ -25,6 +25,7 @@
 #include "JSValue.h"
 #include "identifier.h"
 #include <wtf/Assertions.h>
+#include <wtf/NotFound.h>
 
 namespace KJS {
 
@@ -34,12 +35,11 @@ namespace KJS {
 
 #define KJS_VALUE_SLOT_MARKER 0
 #define KJS_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
-#define KJS_INVALID_OFFSET static_cast<size_t>(-1)
 
     class PropertySlot {
     public:
         PropertySlot()
-            : m_offset(KJS_INVALID_OFFSET)
+            : m_offset(WTF::notFound)
         {
             clearBase();
             clearValue();
@@ -47,7 +47,7 @@ namespace KJS {
 
         explicit PropertySlot(JSValue* base)
             : m_slotBase(base)
-            , m_offset(KJS_INVALID_OFFSET)
+            , m_offset(WTF::notFound)
         {
             clearValue();
         }
@@ -72,7 +72,7 @@ namespace KJS {
             return m_getValue(exec, Identifier::from(exec, propertyName), *this);
         }
 
-        bool isCacheable() const { return m_offset != KJS_INVALID_OFFSET; }
+        bool isCacheable() const { return m_offset != WTF::notFound; }
         size_t cachedOffset() const
         {
             ASSERT(isCacheable());
@@ -219,49 +219,6 @@ namespace KJS {
 
         size_t m_offset;
     };
-    
-    class PutPropertySlot {
-    public:
-        enum SlotType {
-            Invalid,
-            ExistingProperty,
-            NewProperty,
-        };
-
-        PutPropertySlot()
-            : m_type(Invalid)
-            , m_base(0)
-        {
-        }
-
-        void setExistingProperty(JSObject* base, size_t offset)
-        {
-            m_type = ExistingProperty;
-            m_base = base;
-            m_offset = offset;
-        }
-
-        void setNewProperty(JSObject* base, size_t offset)
-        {
-            m_type = NewProperty;
-            m_base = base;
-            m_offset = offset;
-        }
-
-        SlotType type() const { return m_type; }
-        JSObject* slotBase() const { return m_base; }
-
-        bool isCacheable() const { return m_type != Invalid; }
-        size_t cachedOffset() const {
-            ASSERT(isCacheable());
-            return m_offset;
-        }
-
-    private:
-        SlotType m_type;
-        JSObject* m_base;
-        size_t m_offset;
-    };
 
 } // namespace KJS
 
diff --git a/JavaScriptCore/kjs/PutPropertySlot.h b/JavaScriptCore/kjs/PutPropertySlot.h
new file mode 100644 (file)
index 0000000..8eec02b
--- /dev/null
@@ -0,0 +1,77 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef PutPropertySlot_h
+#define PutPropertySlot_h
+
+#include <wtf/Assertions.h>
+
+namespace KJS {
+    
+    class JSObject;
+    
+    class PutPropertySlot {
+    public:
+        enum Type { Invalid, ExistingProperty, NewProperty };
+
+        PutPropertySlot()
+            : m_type(Invalid)
+            , m_base(0)
+        {
+        }
+
+        void setExistingProperty(JSObject* base, size_t offset)
+        {
+            m_type = ExistingProperty;
+            m_base = base;
+            m_offset = offset;
+        }
+
+        void setNewProperty(JSObject* base, size_t offset)
+        {
+            m_type = NewProperty;
+            m_base = base;
+            m_offset = offset;
+        }
+
+        Type type() const { return m_type; }
+        JSObject* base() const { return m_base; }
+
+        bool isCacheable() const { return m_type != Invalid; }
+        size_t cachedOffset() const {
+            ASSERT(isCacheable());
+            return m_offset;
+        }
+
+    private:
+        Type m_type;
+        JSObject* m_base;
+        size_t m_offset;
+    };
+
+} // namespace KJS
+
+#endif // PutPropertySlot_h
index eb8b40b..9619dd5 100644 (file)
@@ -28,7 +28,7 @@
 #include "StructureID.h"
 
 #include "identifier.h"
-#include "JSCell.h"
+#include "JSObject.h"
 #include <wtf/RefPtr.h>
 
 namespace KJS {
@@ -53,7 +53,7 @@ PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structur
         return existingTransition;
 
     if (structureID->m_transitionCount > s_maxTransitionLength)
-        return dictionaryTransition(structureID);
+        return toDictionaryTransition(structureID);
 
     RefPtr<StructureID> transition = create(structureID->m_prototype);
     transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain;
@@ -65,16 +65,26 @@ PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structur
     return transition.release();
 }
 
-PassRefPtr<StructureID> StructureID::dictionaryTransition(StructureID* structureID)
+PassRefPtr<StructureID> StructureID::toDictionaryTransition(StructureID* structureID)
 {
     ASSERT(!structureID->m_isDictionary);
 
     RefPtr<StructureID> transition = create(structureID->m_prototype);
     transition->m_isDictionary = true;
-    transition->m_transitionCount = structureID->m_transitionCount + 1;
     return transition.release();
 }
 
+PassRefPtr<StructureID> StructureID::fromDictionaryTransition(StructureID* structureID)
+{
+    ASSERT(structureID->m_isDictionary);
+
+    // Since dictionary StructureIDs are not shared, and no opcodes specialize
+    // for them, we don't need to allocate a new StructureID when transitioning
+    // to non-dictionary status.
+    structureID->m_isDictionary = false;
+    return structureID;
+}
+
 PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* structureID, JSValue* prototype)
 {
     RefPtr<StructureID> transition = create(prototype);
@@ -98,19 +108,20 @@ StructureID::~StructureID()
 }
 
 StructureIDChain::StructureIDChain(StructureID* structureID)
-    : m_size(0)
 {
+    size_t size = 0;
+
     StructureID* tmp = structureID;
-    while (tmp->prototype() != jsNull()) {
-        ++m_size;
+    while (!tmp->prototype()->isNull()) {
+        ++size;
         tmp = static_cast<JSCell*>(tmp->prototype())->structureID();
     }
 
-    m_vector.set(new RefPtr<StructureID>[m_size]);
+    m_vector.set(new RefPtr<StructureID>[size]);
 
-    for (size_t i = 0; i < m_size; ++i) {
+    for (size_t i = 0; i < size; ++i) {
         m_vector[i] = structureID;
-        structureID = static_cast<JSCell*>(structureID->prototype())->structureID();
+        structureID = static_cast<JSObject*>(structureID->prototype())->structureID();
     }
 }
 
index 44bc60f..3a3f32b 100644 (file)
@@ -48,7 +48,8 @@ namespace KJS {
         static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype);
         static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& name);
         static PassRefPtr<StructureID> getterSetterTransition(StructureID*);
-        static PassRefPtr<StructureID> dictionaryTransition(StructureID*);
+        static PassRefPtr<StructureID> toDictionaryTransition(StructureID*);
+        static PassRefPtr<StructureID> fromDictionaryTransition(StructureID*);
 
         ~StructureID();
 
@@ -66,7 +67,7 @@ namespace KJS {
         StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); }
 
     private:
-        typedef HashMap<RefPtr<UString::Rep>, StructureID*, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> > > TransitionTable;
+        typedef HashMap<RefPtr<UString::Rep>, StructureID*, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> > > TransitionTable;
         
         StructureID(JSValue* prototype);
         
@@ -93,7 +94,6 @@ namespace KJS {
     private:
         StructureIDChain(StructureID* structureID);
 
-        size_t m_size;
         OwnArrayPtr<RefPtr<StructureID> > m_vector;
     };
 
index 4179d80..8163080 100644 (file)
@@ -118,7 +118,7 @@ namespace KJS {
         static const bool needsDestruction = false;
     };
 
-    typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
+    typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
 
 } // namespace KJS
 
index 1503930..82123fb 100644 (file)
@@ -336,6 +336,11 @@ namespace KJS {
         return capacityDelta;
     }
 
+    struct IdentifierRepHash : PtrHash<RefPtr<KJS::UString::Rep> > {
+        static unsigned hash(const RefPtr<KJS::UString::Rep>& key) { return key->computedHash(); }
+        static unsigned hash(KJS::UString::Rep* key) { return key->computedHash(); }
+    };
+
 } // namespace KJS
 
 namespace WTF {
@@ -369,11 +374,6 @@ namespace WTF {
 
     };
 
-    struct IdentifierRepHash : PtrHash<RefPtr<KJS::UString::Rep> > {
-        static unsigned hash(const RefPtr<KJS::UString::Rep>& key) { return key->computedHash(); }
-        static unsigned hash(KJS::UString::Rep* key) { return key->computedHash(); }
-    };
-
 } // namespace WTF
 
 #endif
index bd85c5a..6d7f3ce 100644 (file)
@@ -1,3 +1,12 @@
+2008-09-02  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Sam Weinig.
+        
+        Implemented the rest of Darin's review comments for the 09-01 inline
+        caching patch.
+        
+        * ForwardingHeaders/kjs/PutPropertySlot.h: Added.
+
 2008-09-01  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Darin Adler.
diff --git a/JavaScriptGlue/ForwardingHeaders/kjs/PutPropertySlot.h b/JavaScriptGlue/ForwardingHeaders/kjs/PutPropertySlot.h
new file mode 100644 (file)
index 0000000..237081b
--- /dev/null
@@ -0,0 +1 @@
+#include <JavaScriptCore/PutPropertySlot.h>
diff --git a/JavaScriptGlue/ForwardingHeaders/wtf/NotFound.h b/JavaScriptGlue/ForwardingHeaders/wtf/NotFound.h
new file mode 100644 (file)
index 0000000..cfe1896
--- /dev/null
@@ -0,0 +1 @@
+#include <JavaScriptCore/NotFound.h>