[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

oliver at apple.com oliver at apple.com
Thu Apr 8 02:10:45 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 2f94c2a02361f06839e333c2768d7ca0d2c80623
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Mar 5 01:33:54 2010 +0000

    2010-03-03  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Allow static property getters to interact with JSCs caching
            https://bugs.webkit.org/show_bug.cgi?id=35716
    
            Add new opcodes for handling cached lookup of static value getters.
            More or less the same as with JS getters, all that changes is that
            instead of calling through a JSFunction we always know that we have
            a C function to call.
    
            For the patching routines in the JIT we now need to pass a few
            new parameters to allow us to pass enough information to the stub
            function to allow us to call the C function correctly.  Logically
            this shouldn't actually be necessary as all of these functions ignore
            the identifier, but removing the ident parameter would require
            somewhat involved changes to the way we implement getOwnPropertySlot,
            etc.
    
            * bytecode/CodeBlock.cpp:
            (JSC::CodeBlock::dump):
            (JSC::CodeBlock::derefStructures):
            (JSC::CodeBlock::refStructures):
            * bytecode/Instruction.h:
            (JSC::Instruction::Instruction):
            (JSC::Instruction::):
            * bytecode/Opcode.h:
            * interpreter/Interpreter.cpp:
            (JSC::Interpreter::tryCacheGetByID):
            (JSC::Interpreter::privateExecute):
            * jit/JIT.cpp:
            (JSC::JIT::privateCompileMainPass):
            * jit/JIT.h:
            (JSC::JIT::compileGetByIdProto):
            (JSC::JIT::compileGetByIdSelfList):
            (JSC::JIT::compileGetByIdProtoList):
            (JSC::JIT::compileGetByIdChainList):
            (JSC::JIT::compileGetByIdChain):
            * jit/JITPropertyAccess.cpp:
            (JSC::JIT::privateCompileGetByIdProto):
            (JSC::JIT::privateCompileGetByIdSelfList):
            (JSC::JIT::privateCompileGetByIdProtoList):
            (JSC::JIT::privateCompileGetByIdChainList):
            (JSC::JIT::privateCompileGetByIdChain):
            * jit/JITPropertyAccess32_64.cpp:
            (JSC::JIT::privateCompileGetByIdProto):
            (JSC::JIT::privateCompileGetByIdSelfList):
            (JSC::JIT::privateCompileGetByIdProtoList):
            (JSC::JIT::privateCompileGetByIdChainList):
            (JSC::JIT::privateCompileGetByIdChain):
            * jit/JITStubs.cpp:
            (JSC::JITThunks::tryCacheGetByID):
            (JSC::DEFINE_STUB_FUNCTION):
            * jit/JITStubs.h:
            (JSC::):
            * runtime/JSFunction.cpp:
            (JSC::JSFunction::getOwnPropertySlot):
            * runtime/Lookup.h:
            (JSC::getStaticPropertySlot):
            (JSC::getStaticValueSlot):
            * runtime/PropertySlot.h:
            (JSC::PropertySlot::):
            (JSC::PropertySlot::PropertySlot):
            (JSC::PropertySlot::cachedPropertyType):
            (JSC::PropertySlot::isCacheable):
            (JSC::PropertySlot::isCacheableValue):
            (JSC::PropertySlot::setValueSlot):
            (JSC::PropertySlot::setCacheableCustom):
            (JSC::PropertySlot::setGetterSlot):
            (JSC::PropertySlot::setCacheableGetterSlot):
            (JSC::PropertySlot::clearOffset):
            (JSC::PropertySlot::customGetter):
    2010-03-03  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Allow static property getters to interact with JSCs caching
            https://bugs.webkit.org/show_bug.cgi?id=35716
    
            Add tests to ensure nothing horrifying happens to static property
            getters if they're in a path where we end up caching lookups.
    
            * fast/js/pic/cached-named-property-getter-expected.txt: Added.
            * fast/js/pic/cached-named-property-getter.html: Added.
    2010-03-03  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Allow static property getters to interact with JSCs caching
            https://bugs.webkit.org/show_bug.cgi?id=35716
    
            Update the obviously safe getters to allow caching
    
            Test: fast/js/pic/cached-named-property-getter.html
    
            * bridge/runtime_array.cpp:
            (JSC::RuntimeArray::getOwnPropertySlot):
            * bridge/runtime_method.cpp:
            (JSC::RuntimeMethod::getOwnPropertySlot):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@55564 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 25257f1..c91e29c 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,77 @@
+2010-03-03  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Allow static property getters to interact with JSCs caching
+        https://bugs.webkit.org/show_bug.cgi?id=35716
+
+        Add new opcodes for handling cached lookup of static value getters.
+        More or less the same as with JS getters, all that changes is that
+        instead of calling through a JSFunction we always know that we have
+        a C function to call.
+
+        For the patching routines in the JIT we now need to pass a few
+        new parameters to allow us to pass enough information to the stub
+        function to allow us to call the C function correctly.  Logically
+        this shouldn't actually be necessary as all of these functions ignore
+        the identifier, but removing the ident parameter would require
+        somewhat involved changes to the way we implement getOwnPropertySlot,
+        etc.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::derefStructures):
+        (JSC::CodeBlock::refStructures):
+        * bytecode/Instruction.h:
+        (JSC::Instruction::Instruction):
+        (JSC::Instruction::):
+        * bytecode/Opcode.h:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::tryCacheGetByID):
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        (JSC::JIT::compileGetByIdProto):
+        (JSC::JIT::compileGetByIdSelfList):
+        (JSC::JIT::compileGetByIdProtoList):
+        (JSC::JIT::compileGetByIdChainList):
+        (JSC::JIT::compileGetByIdChain):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::privateCompileGetByIdProto):
+        (JSC::JIT::privateCompileGetByIdSelfList):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        (JSC::JIT::privateCompileGetByIdChain):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::privateCompileGetByIdProto):
+        (JSC::JIT::privateCompileGetByIdSelfList):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        (JSC::JIT::privateCompileGetByIdChain):
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::tryCacheGetByID):
+        (JSC::DEFINE_STUB_FUNCTION):
+        * jit/JITStubs.h:
+        (JSC::):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::getOwnPropertySlot):
+        * runtime/Lookup.h:
+        (JSC::getStaticPropertySlot):
+        (JSC::getStaticValueSlot):
+        * runtime/PropertySlot.h:
+        (JSC::PropertySlot::):
+        (JSC::PropertySlot::PropertySlot):
+        (JSC::PropertySlot::cachedPropertyType):
+        (JSC::PropertySlot::isCacheable):
+        (JSC::PropertySlot::isCacheableValue):
+        (JSC::PropertySlot::setValueSlot):
+        (JSC::PropertySlot::setCacheableCustom):
+        (JSC::PropertySlot::setGetterSlot):
+        (JSC::PropertySlot::setCacheableGetterSlot):
+        (JSC::PropertySlot::clearOffset):
+        (JSC::PropertySlot::customGetter):
+
 2010-03-04  Shinichiro Hamaji  <hamaji at chromium.org>
 
         Unreviewed. Remove a non-ASCII character introduced in the following bug.
diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp
index 68debb2..1f090a4 100644
--- a/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -785,6 +785,26 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
             break;
         }
+        case op_get_by_id_custom_self: {
+            printGetByIdOp(exec, location, it, "get_by_id_custom_self");
+            break;
+        }
+        case op_get_by_id_custom_self_list: {
+            printGetByIdOp(exec, location, it, "get_by_id_custom_self_list");
+            break;
+        }
+        case op_get_by_id_custom_proto: {
+            printGetByIdOp(exec, location, it, "get_by_id_custom_proto");
+            break;
+        }
+        case op_get_by_id_custom_proto_list: {
+            printGetByIdOp(exec, location, it, "get_by_id_custom_proto_list");
+            break;
+        }
+        case op_get_by_id_custom_chain: {
+            printGetByIdOp(exec, location, it, "get_by_id_custom_chain");
+            break;
+        }
         case op_get_by_id_generic: {
             printGetByIdOp(exec, location, it, "get_by_id_generic");
             break;
@@ -1375,7 +1395,7 @@ void CodeBlock::derefStructures(Instruction* vPC) const
 {
     Interpreter* interpreter = m_globalData->interpreter;
 
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
         vPC[4].u.structure->deref();
         return;
     }
@@ -1422,7 +1442,7 @@ void CodeBlock::refStructures(Instruction* vPC) const
 {
     Interpreter* interpreter = m_globalData->interpreter;
 
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
         vPC[4].u.structure->ref();
         return;
     }
diff --git a/JavaScriptCore/bytecode/Instruction.h b/JavaScriptCore/bytecode/Instruction.h
index bcef7fb..ab6659f 100644
--- a/JavaScriptCore/bytecode/Instruction.h
+++ b/JavaScriptCore/bytecode/Instruction.h
@@ -31,6 +31,7 @@
 
 #include "MacroAssembler.h"
 #include "Opcode.h"
+#include "PropertySlot.h"
 #include "Structure.h"
 #include <wtf/VectorTraits.h>
 
@@ -144,6 +145,7 @@ namespace JSC {
         Instruction(StructureChain* structureChain) { u.structureChain = structureChain; }
         Instruction(JSCell* jsCell) { u.jsCell = jsCell; }
         Instruction(PolymorphicAccessStructureList* polymorphicStructures) { u.polymorphicStructures = polymorphicStructures; }
+        Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; }
 
         union {
             Opcode opcode;
@@ -152,6 +154,7 @@ namespace JSC {
             StructureChain* structureChain;
             JSCell* jsCell;
             PolymorphicAccessStructureList* polymorphicStructures;
+            PropertySlot::GetValueFunc getterFunc;
         } u;
     };
 
diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h
index 56555f3..509daeb 100644
--- a/JavaScriptCore/bytecode/Opcode.h
+++ b/JavaScriptCore/bytecode/Opcode.h
@@ -109,6 +109,11 @@ namespace JSC {
         macro(op_get_by_id_getter_proto, 8) \
         macro(op_get_by_id_getter_proto_list, 8) \
         macro(op_get_by_id_getter_chain, 8) \
+        macro(op_get_by_id_custom_self, 8) \
+        macro(op_get_by_id_custom_self_list, 8) \
+        macro(op_get_by_id_custom_proto, 8) \
+        macro(op_get_by_id_custom_proto_list, 8) \
+        macro(op_get_by_id_custom_chain, 8) \
         macro(op_get_by_id_generic, 8) \
         macro(op_get_array_length, 8) \
         macro(op_get_string_length, 8) \
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 8e05c12..c671382 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -1030,8 +1030,20 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
     // Cache hit: Specialize instruction and ref Structures.
 
     if (slot.slotBase() == baseValue) {
-        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_self) : getOpcode(op_get_by_id_self);
-        vPC[5] = slot.cachedOffset();
+        switch (slot.cachedPropertyType()) {
+        case PropertySlot::Getter:
+            vPC[0] = getOpcode(op_get_by_id_getter_self);
+            vPC[5] = slot.cachedOffset();
+            break;
+        case PropertySlot::Custom:
+            vPC[0] = getOpcode(op_get_by_id_custom_self);
+            vPC[5] = slot.customGetter();
+            break;
+        default:
+            vPC[0] = getOpcode(op_get_by_id_self);
+            vPC[5] = slot.cachedOffset();
+            break;
+        }
 
         codeBlock->refStructures(vPC);
         return;
@@ -1056,10 +1068,22 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
         }
 
         ASSERT(!baseObject->structure()->isUncacheableDictionary());
-
-        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_proto) : getOpcode(op_get_by_id_proto);
+        
+        switch (slot.cachedPropertyType()) {
+        case PropertySlot::Getter:
+            vPC[0] = getOpcode(op_get_by_id_getter_proto);
+            vPC[6] = offset;
+            break;
+        case PropertySlot::Custom:
+            vPC[0] = getOpcode(op_get_by_id_custom_proto);
+            vPC[6] = slot.customGetter();
+            break;
+        default:
+            vPC[0] = getOpcode(op_get_by_id_proto);
+            vPC[6] = offset;
+            break;
+        }
         vPC[5] = baseObject->structure();
-        vPC[6] = offset;
 
         codeBlock->refStructures(vPC);
         return;
@@ -1072,11 +1096,24 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
         return;
     }
 
-    vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_chain) : getOpcode(op_get_by_id_chain);
+    
+    switch (slot.cachedPropertyType()) {
+    case PropertySlot::Getter:
+        vPC[0] = getOpcode(op_get_by_id_getter_chain);
+        vPC[7] = offset;
+        break;
+    case PropertySlot::Custom:
+        vPC[0] = getOpcode(op_get_by_id_custom_chain);
+        vPC[7] = slot.customGetter();
+        break;
+    default:
+        vPC[0] = getOpcode(op_get_by_id_chain);
+        vPC[7] = offset;
+        break;
+    }
     vPC[4] = structure;
     vPC[5] = structure->prototypeChain(callFrame);
     vPC[6] = count;
-    vPC[7] = offset;
     codeBlock->refStructures(vPC);
 }
 
@@ -2207,6 +2244,48 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
 #if HAVE(COMPUTED_GOTO)
     skip_id_getter_proto:
 #endif
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_custom_proto);
+#endif
+    DEFINE_OPCODE(op_get_by_id_custom_proto) {
+        /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
+         
+         Cached property access: Attempts to use a cached named property getter
+         from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
+         reverts to op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                ASSERT(structure->prototypeForLookup(callFrame).isObject());
+                JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
+                Structure* prototypeStructure = vPC[5].u.structure;
+                
+                if (LIKELY(protoObject->structure() == prototypeStructure)) {
+                    int dst = vPC[1].u.operand;
+                    int property = vPC[3].u.operand;
+                    Identifier& ident = callFrame->codeBlock()->identifier(property);
+                    
+                    PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
+                    JSValue result = getter(callFrame, protoObject, ident);
+                    CHECK_FOR_EXCEPTION();
+                    callFrame->r(dst) = result;
+                    vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
+                    NEXT_INSTRUCTION();
+                }
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+    skip_id_custom_proto:
+#endif
     DEFINE_OPCODE(op_get_by_id_self_list) {
         // Polymorphic self access caching currently only supported when JITting.
         ASSERT_NOT_REACHED();
@@ -2235,6 +2314,20 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_get_by_id_custom_self_list) {
+        // Polymorphic self access caching currently only supported when JITting.
+        ASSERT_NOT_REACHED();
+        // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
+        vPC += OPCODE_LENGTH(op_get_by_id_custom_self_list);
+        NEXT_INSTRUCTION();
+    }
+    DEFINE_OPCODE(op_get_by_id_custom_proto_list) {
+        // Polymorphic prototype access caching currently only supported when JITting.
+        ASSERT_NOT_REACHED();
+        // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
+        vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_get_by_id_chain) {
         /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
 
@@ -2324,6 +2417,43 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
 #if HAVE(COMPUTED_GOTO)
     skip_id_getter_self:
 #endif
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_custom_self);
+#endif
+    DEFINE_OPCODE(op_get_by_id_custom_self) {
+        /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
+         
+         Cached property access: Attempts to use a cached named property getter
+         from the value base. If the cache misses, op_get_by_id_custom_self reverts to
+         op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                ASSERT(baseCell->isObject());
+                int dst = vPC[1].u.operand;
+                int property = vPC[3].u.operand;
+                Identifier& ident = callFrame->codeBlock()->identifier(property);
+
+                PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
+                JSValue result = getter(callFrame, baseValue, ident);
+                CHECK_FOR_EXCEPTION();
+                callFrame->r(dst) = result;
+                vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
+                NEXT_INSTRUCTION();
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+skip_id_custom_self:
+#endif
     DEFINE_OPCODE(op_get_by_id_generic) {
         /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
 
@@ -2399,6 +2529,58 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
 #if HAVE(COMPUTED_GOTO)
     skip_id_getter_chain:
 #endif
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_custom_chain);
+#endif
+    DEFINE_OPCODE(op_get_by_id_custom_chain) {
+        /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
+         
+         Cached property access: Attempts to use a cached named property getter on the
+         value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
+         reverts to op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+                size_t count = vPC[6].u.operand;
+                RefPtr<Structure>* end = it + count;
+                
+                while (true) {
+                    JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
+                    
+                    if (UNLIKELY(baseObject->structure() != (*it).get()))
+                        break;
+                    
+                    if (++it == end) {
+                        int dst = vPC[1].u.operand;
+                        int property = vPC[3].u.operand;
+                        Identifier& ident = callFrame->codeBlock()->identifier(property);
+                        
+                        PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
+                        JSValue result = getter(callFrame, baseObject, ident);
+                        CHECK_FOR_EXCEPTION();
+                        callFrame->r(dst) = result;
+                        vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
+                        NEXT_INSTRUCTION();
+                    }
+                    
+                    // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
+                    baseCell = baseObject;
+                }
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+    skip_id_custom_chain:
+#endif
     DEFINE_OPCODE(op_get_array_length) {
         /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
 
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index 78c5153..b414101 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -327,6 +327,11 @@ void JIT::privateCompileMainPass()
         case op_get_by_id_getter_proto_list:
         case op_get_by_id_getter_self:
         case op_get_by_id_getter_self_list:
+        case op_get_by_id_custom_chain:
+        case op_get_by_id_custom_proto:
+        case op_get_by_id_custom_proto_list:
+        case op_get_by_id_custom_self:
+        case op_get_by_id_custom_self_list:
         case op_get_string_length:
         case op_put_by_id_generic:
         case op_put_by_id_replace:
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index 37c95b9..87dd485 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -283,32 +283,32 @@ namespace JSC {
             return JIT(globalData, codeBlock).privateCompile();
         }
 
-        static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress)
+        static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
         {
             JIT jit(globalData, codeBlock);
-            jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, isGetter, cachedOffset, returnAddress, callFrame);
+            jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame);
         }
 
-        static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, bool isGetter, size_t cachedOffset)
+        static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
         {
             JIT jit(globalData, codeBlock);
-            jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, isGetter, cachedOffset);
+            jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, ident, slot, cachedOffset);
         }
-        static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset)
+        static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
         {
             JIT jit(globalData, codeBlock);
-            jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, isGetter, cachedOffset, callFrame);
+            jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, ident, slot, cachedOffset, callFrame);
         }
-        static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset)
+        static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
         {
             JIT jit(globalData, codeBlock);
-            jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, isGetter, cachedOffset, callFrame);
+            jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, ident, slot, cachedOffset, callFrame);
         }
 
-        static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress)
+        static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
         {
             JIT jit(globalData, codeBlock);
-            jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, isGetter, cachedOffset, returnAddress, callFrame);
+            jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame);
         }
         
         static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress)
@@ -354,11 +354,11 @@ namespace JSC {
         void privateCompileLinkPass();
         void privateCompileSlowCases();
         JITCode privateCompile();
-        void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
-        void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, bool isGetter, size_t cachedOffset);
-        void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, CallFrame* callFrame);
-        void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, CallFrame* callFrame);
-        void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
+        void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
+        void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
+        void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
+        void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
+        void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
         void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress);
 
         void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, TrampolineStructure *trampolines);
diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp
index 8f1ddbb..3399f03 100644
--- a/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -696,7 +696,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
 }
 
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
 {
     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
     // referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -714,14 +714,25 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
 
+    bool needsStubLink = false;
+    
     // Checks out okay!
-    if (isGetter) {
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
     Jump success = jump();
@@ -735,7 +746,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
 
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -754,10 +765,12 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
 }
 
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, bool isGetter, size_t cachedOffset)
+void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
 {
     Jump failureCase = checkStructure(regT0, structure);
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         if (!structure->isUsingInlineStorage()) {
             move(regT0, regT1);
             compileGetDirectOffset(regT1, regT1, structure, cachedOffset);
@@ -768,13 +781,21 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(regT0);
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
     Jump success = jump();
 
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
 
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -802,7 +823,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
 {
     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
     // referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -821,13 +842,23 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
 #endif
 
     // Checks out okay!
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
 
@@ -835,7 +866,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
 
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
 
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -862,7 +893,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
 {
     ASSERT(count);
     JumpList bucketsOfFail;
@@ -889,20 +920,30 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     }
     ASSERT(protoObject);
     
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
     Jump success = jump();
 
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
     
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -930,7 +971,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
 {
     ASSERT(count);
 
@@ -956,21 +997,31 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
 #endif
     }
     ASSERT(protoObject);
-    
-    if (isGetter) {
+
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
     Jump success = jump();
 
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
 
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
diff --git a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index d1bb449..ec33026 100644
--- a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -718,7 +718,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
 }
 
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
 {
     // regT0 holds a JSCell*
     
@@ -736,15 +736,24 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
 #else
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
-    
+    bool needsStubLink = false;
     // Checks out okay!
-    if (isGetter) {
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
     
@@ -760,7 +769,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
     patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
 
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -781,11 +790,13 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
 }
 
 
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, bool isGetter, size_t cachedOffset)
+void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
 {
     // regT0 holds a JSCell*
     Jump failureCase = checkStructure(regT0, structure);
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         if (!structure->isUsingInlineStorage()) {
             move(regT0, regT1);
             compileGetDirectOffset(regT1, regT2, regT1, structure, cachedOffset);
@@ -796,13 +807,21 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(regT0);
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(regT0, regT1, regT0, structure, cachedOffset);
 
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -829,7 +848,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, bool isGetter, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
 {
     // regT0 holds a JSCell*
     
@@ -849,20 +868,30 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
     
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
     
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -888,7 +917,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
 {
     // regT0 holds a JSCell*
     ASSERT(count);
@@ -916,20 +945,30 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     }
     ASSERT(protoObject);
     
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
 
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
@@ -956,7 +995,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
     repatchBuffer.relink(jumpLocation, entryLabel);
 }
 
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, bool isGetter, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
 {
     // regT0 holds a JSCell*
     ASSERT(count);
@@ -984,19 +1023,29 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
     }
     ASSERT(protoObject);
     
-    if (isGetter) {
+    bool needsStubLink = false;
+    if (slot.cachedPropertyType() == PropertySlot::Getter) {
+        needsStubLink = true;
         compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
         JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
         stubCall.addArgument(regT1);
         stubCall.addArgument(regT0);
         stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
         stubCall.call();
+    } else if (slot.cachedPropertyType() == PropertySlot::Custom) {
+        needsStubLink = true;
+        JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
+        stubCall.addArgument(ImmPtr(protoObject));
+        stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+        stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
+        stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+        stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-    if (isGetter) {
+    if (needsStubLink) {
         for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
             if (iter->to)
                 patchBuffer.link(iter->from, FunctionPtr(iter->to));
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 94cbddb..fa3fc0a 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -875,7 +875,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
     if (slot.slotBase() == baseValue) {
         // set this up, so derefStructures can do it's job.
         stubInfo->initGetByIdSelf(structure);
-        if (slot.isGetter())
+        if (slot.cachedPropertyType() != PropertySlot::Value)
             ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
         else
             JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
@@ -904,7 +904,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
 
         ASSERT(!structure->isDictionary());
         ASSERT(!slotBaseObject->structure()->isDictionary());
-        JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), slot.isGetter(), offset, returnAddress);
+        JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress);
         return;
     }
 
@@ -917,7 +917,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
 
     StructureChain* prototypeChain = structure->prototypeChain(callFrame);
     stubInfo->initGetByIdChain(structure, prototypeChain);
-    JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.isGetter(), offset, returnAddress);
+    JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
 }
 
 #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
@@ -1399,7 +1399,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
             stubInfo->u.getByIdSelfList.listSize++;
         }
 
-        JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.isGetter(), slot.cachedOffset());
+        JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset());
 
         if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
@@ -1454,6 +1454,20 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub)
     return JSValue::encode(result);
 }
 
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_custom_stub)
+{
+    STUB_INIT_STACK_FRAME(stackFrame);
+    CallFrame* callFrame = stackFrame.callFrame;
+    JSObject* slotBase = stackFrame.args[0].jsObject();
+    PropertySlot::GetValueFunc getter = reinterpret_cast<PropertySlot::GetValueFunc>(stackFrame.args[1].asPointer);
+    const Identifier& ident = stackFrame.args[2].identifier();
+    JSValue result = getter(callFrame, slotBase, ident);
+    if (callFrame->hadException())
+        returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[3].returnAddress(), STUB_RETURN_ADDRESS);
+    
+    return JSValue::encode(result);
+}
+
 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
@@ -1495,7 +1509,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
         int listIndex;
         PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
 
-        JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.isGetter(), offset);
+        JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset);
 
         if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
@@ -1505,7 +1519,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
         PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
 
         StructureChain* protoChain = structure->prototypeChain(callFrame);
-        JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.isGetter(), offset);
+        JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset);
 
         if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h
index 751cd0a..c33d6f0 100644
--- a/JavaScriptCore/jit/JITStubs.h
+++ b/JavaScriptCore/jit/JITStubs.h
@@ -277,6 +277,7 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_get_by_id_generic(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_get_by_id_getter_stub(STUB_ARGS_DECLARATION);
+    EncodedJSValue JIT_STUB cti_op_get_by_id_custom_stub(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list_full(STUB_ARGS_DECLARATION);
diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp
index b8ca594..cba6795 100644
--- a/JavaScriptCore/runtime/JSFunction.cpp
+++ b/JavaScriptCore/runtime/JSFunction.cpp
@@ -162,17 +162,17 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
     }
 
     if (propertyName == exec->propertyNames().arguments) {
-        slot.setCustom(this, argumentsGetter);
+        slot.setCacheableCustom(this, argumentsGetter);
         return true;
     }
 
     if (propertyName == exec->propertyNames().length) {
-        slot.setCustom(this, lengthGetter);
+        slot.setCacheableCustom(this, lengthGetter);
         return true;
     }
 
     if (propertyName == exec->propertyNames().caller) {
-        slot.setCustom(this, callerGetter);
+        slot.setCacheableCustom(this, callerGetter);
         return true;
     }
 
diff --git a/JavaScriptCore/runtime/Lookup.h b/JavaScriptCore/runtime/Lookup.h
index e673c09..995aeee 100644
--- a/JavaScriptCore/runtime/Lookup.h
+++ b/JavaScriptCore/runtime/Lookup.h
@@ -181,7 +181,7 @@ namespace JSC {
         if (entry->attributes() & Function)
             setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
         else
-            slot.setCustom(thisObj, entry->propertyGetter());
+            slot.setCacheableCustom(thisObj, entry->propertyGetter());
 
         return true;
     }
@@ -258,7 +258,7 @@ namespace JSC {
 
         ASSERT(!(entry->attributes() & Function));
 
-        slot.setCustom(thisObj, entry->propertyGetter());
+        slot.setCacheableCustom(thisObj, entry->propertyGetter());
         return true;
     }
 
diff --git a/JavaScriptCore/runtime/PropertySlot.h b/JavaScriptCore/runtime/PropertySlot.h
index a9d5b0a..de9ddc9 100644
--- a/JavaScriptCore/runtime/PropertySlot.h
+++ b/JavaScriptCore/runtime/PropertySlot.h
@@ -39,7 +39,15 @@ namespace JSC {
 
     class PropertySlot {
     public:
+        enum CachedPropertyType {
+            Uncacheable,
+            Getter,
+            Custom,
+            Value
+        };
+
         PropertySlot()
+            : m_cachedPropertyType(Uncacheable)
         {
             clearBase();
             clearOffset();
@@ -48,6 +56,7 @@ namespace JSC {
 
         explicit PropertySlot(const JSValue base)
             : m_slotBase(base)
+            , m_cachedPropertyType(Uncacheable)
         {
             clearOffset();
             clearValue();
@@ -82,9 +91,9 @@ namespace JSC {
             return m_getValue(exec, slotBase(), Identifier::from(exec, propertyName));
         }
 
-        bool isGetter() const { return m_isGetter; }
-        bool isCacheable() const { return m_isCacheable; }
-        bool isCacheableValue() const { return m_isCacheable && !m_isGetter; }
+        CachedPropertyType cachedPropertyType() const { return m_cachedPropertyType; }
+        bool isCacheable() const { return m_cachedPropertyType != Uncacheable; }
+        bool isCacheableValue() const { return m_cachedPropertyType == Value; }
         size_t cachedOffset() const
         {
             ASSERT(isCacheable());
@@ -115,8 +124,7 @@ namespace JSC {
             m_slotBase = slotBase;
             m_data.valueSlot = valueSlot;
             m_offset = offset;
-            m_isCacheable = true;
-            m_isGetter = false;
+            m_cachedPropertyType = Value;
         }
         
         void setValue(JSValue value)
@@ -146,6 +154,16 @@ namespace JSC {
             m_getIndexValue = 0;
             m_slotBase = slotBase;
         }
+        
+        void setCacheableCustom(JSValue slotBase, GetValueFunc getValue)
+        {
+            ASSERT(slotBase);
+            ASSERT(getValue);
+            m_getValue = getValue;
+            m_getIndexValue = 0;
+            m_slotBase = slotBase;
+            m_cachedPropertyType = Custom;
+        }
 
         void setCustomIndex(JSValue slotBase, unsigned index, GetIndexValueFunc getIndexValue)
         {
@@ -163,7 +181,6 @@ namespace JSC {
             m_thisValue = m_slotBase;
             m_getValue = GETTER_FUNCTION_MARKER;
             m_data.getterFunc = getterFunc;
-            m_isGetter = true;
         }
 
         void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, unsigned offset)
@@ -174,8 +191,7 @@ namespace JSC {
             m_slotBase = slotBase;
             m_data.getterFunc = getterFunc;
             m_offset = offset;
-            m_isCacheable = true;
-            m_isGetter = true;
+            m_cachedPropertyType = Getter;
         }
 
         void setUndefined()
@@ -214,13 +230,18 @@ namespace JSC {
             // Clear offset even in release builds, in case this PropertySlot has been used before.
             // (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.)
             m_offset = 0;
-            m_isCacheable = false;
-            m_isGetter = false;
+            m_cachedPropertyType = Uncacheable;
         }
 
         unsigned index() const { return m_data.index; }
 
         JSValue thisValue() const { return m_thisValue; }
+
+        GetValueFunc customGetter() const
+        {
+            ASSERT(m_cachedPropertyType == Custom);
+            return m_getValue;
+        }
     private:
         JSValue functionGetter(ExecState*) const;
 
@@ -239,8 +260,7 @@ namespace JSC {
         JSValue m_thisValue;
 
         size_t m_offset;
-        bool m_isCacheable : 1;
-        bool m_isGetter : 1;
+        CachedPropertyType m_cachedPropertyType;
     };
 
 } // namespace JSC
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 1ea7f80..cb33490 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,16 @@
+2010-03-03  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Allow static property getters to interact with JSCs caching
+        https://bugs.webkit.org/show_bug.cgi?id=35716
+
+        Add tests to ensure nothing horrifying happens to static property
+        getters if they're in a path where we end up caching lookups.
+
+        * fast/js/pic/cached-named-property-getter-expected.txt: Added.
+        * fast/js/pic/cached-named-property-getter.html: Added.
+
 2010-03-04  James Robinson  <jamesr at chromium.org>
 
         Reviewed by Dimitri Glazkov.
diff --git a/LayoutTests/fast/js/pic/cached-named-property-getter-expected.txt b/LayoutTests/fast/js/pic/cached-named-property-getter-expected.txt
new file mode 100644
index 0000000..261b606
--- /dev/null
+++ b/LayoutTests/fast/js/pic/cached-named-property-getter-expected.txt
@@ -0,0 +1,12 @@
+This page tests cached access to getters and setters. If the test passes, you'll see a series of PASS messages below.
+
+PASS: testGetter({__proto__: {count: 'FAIL'}, get length(){ return this.count; }, count: 7}) should be 7 and is.
+PASS: testGetter(testFunction3) should be 3 and is.
+PASS: testGetter(testFunction5) should be 5 and is.
+PASS: testProtoGetter({__proto__: {count: 'FAIL', get length(){ return this.count; }}, count: 7}) should be 7 and is.
+PASS: testProtoGetter({__proto__: testFunction3, count: 'FAIL'}) should be 3 and is.
+PASS: testProtoGetter({__proto__: testFunction5, count: 'FAIL'}) should be 5 and is.
+PASS: testProtoChainGetter({__proto__: {__proto__: {count: 'FAIL', get length(){ return this.count; }}}, count: 7}) should be 7 and is.
+PASS: testProtoChainGetter({__proto__: {__proto__: testFunction3}, count: 'FAIL'}) should be 3 and is.
+PASS: testProtoChainGetter({__proto__: {__proto__: testFunction5}, count: 'FAIL'}) should be 5 and is.
+
diff --git a/LayoutTests/fast/js/pic/cached-named-property-getter.html b/LayoutTests/fast/js/pic/cached-named-property-getter.html
new file mode 100644
index 0000000..ef6a87b
--- /dev/null
+++ b/LayoutTests/fast/js/pic/cached-named-property-getter.html
@@ -0,0 +1,66 @@
+<p>
+This page tests cached access to getters and setters. If the test passes,
+you'll see a series of PASS messages below.
+</p>
+
+<pre id="console"></pre>
+
+<script>
+(function() {
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+
+    function log(s)
+    {
+        if (this.document)
+            document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
+        else
+            print(s + "\n");
+    }
+    
+    function shouldBe(a, aDescription, b)
+    {
+        if (a === b) {
+            log("PASS: " + aDescription + " should be " + b + " and is.");
+        } else {
+            log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
+        }
+    }
+    
+    function testGetter(o) {
+        var result;
+        for (var i = 0; i < 10; i++)
+            result = o.length;
+        return result;
+    }
+    function testProtoGetter(o) {
+        var result;
+        for (var i = 0; i < 10; i++)
+            result = o.length;
+        return result;
+    }
+    function testProtoChainGetter(o) {
+        var result;
+        for (var i = 0; i < 10; i++)
+            result = o.length;
+        return result;
+    }
+    function getterTest(str, expected) {
+        shouldBe(eval(str), str, expected);
+    }
+    var testFunction3 = function(a,b,c){}
+    var testFunction5 = function(a,b,c,d,e){}
+    getterTest("testGetter({__proto__: {count: 'FAIL'}, get length(){ return this.count; }, count: 7})", 7);
+    getterTest("testGetter(testFunction3)", 3);
+    getterTest("testGetter(testFunction5)", 5);
+    
+    getterTest("testProtoGetter({__proto__: {count: 'FAIL', get length(){ return this.count; }}, count: 7})", 7);
+    getterTest("testProtoGetter({__proto__: testFunction3, count: 'FAIL'})", 3);
+    getterTest("testProtoGetter({__proto__: testFunction5, count: 'FAIL'})", 5);
+
+    getterTest("testProtoChainGetter({__proto__: {__proto__: {count: 'FAIL', get length(){ return this.count; }}}, count: 7})", 7);
+    getterTest("testProtoChainGetter({__proto__: {__proto__: testFunction3}, count: 'FAIL'})", 3);
+    getterTest("testProtoChainGetter({__proto__: {__proto__: testFunction5}, count: 'FAIL'})", 5);
+
+})();
+</script>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index fee2951..be02ba5 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,19 @@
+2010-03-03  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Allow static property getters to interact with JSCs caching
+        https://bugs.webkit.org/show_bug.cgi?id=35716
+
+        Update the obviously safe getters to allow caching
+
+        Test: fast/js/pic/cached-named-property-getter.html
+
+        * bridge/runtime_array.cpp:
+        (JSC::RuntimeArray::getOwnPropertySlot):
+        * bridge/runtime_method.cpp:
+        (JSC::RuntimeMethod::getOwnPropertySlot):
+
 2010-03-04  Mark Rowe  <mrowe at apple.com>
 
         Reviewed by Sam Weinig.
diff --git a/WebCore/bridge/runtime_array.cpp b/WebCore/bridge/runtime_array.cpp
index 6b8059f..1f2bfe7 100644
--- a/WebCore/bridge/runtime_array.cpp
+++ b/WebCore/bridge/runtime_array.cpp
@@ -77,7 +77,7 @@ void RuntimeArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& prope
 bool RuntimeArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
     if (propertyName == exec->propertyNames().length) {
-        slot.setCustom(this, lengthGetter);
+        slot.setCacheableCustom(this, lengthGetter);
         return true;
     }
     
diff --git a/WebCore/bridge/runtime_method.cpp b/WebCore/bridge/runtime_method.cpp
index cbe64c8..29145b6 100644
--- a/WebCore/bridge/runtime_method.cpp
+++ b/WebCore/bridge/runtime_method.cpp
@@ -68,7 +68,7 @@ JSValue RuntimeMethod::lengthGetter(ExecState* exec, JSValue slotBase, const Ide
 bool RuntimeMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
 {
     if (propertyName == exec->propertyNames().length) {
-        slot.setCustom(this, lengthGetter);
+        slot.setCacheableCustom(this, lengthGetter);
         return true;
     }
     

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list