[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.15.1-1414-gc69ee75

mrowe at apple.com mrowe at apple.com
Thu Oct 29 20:46:39 UTC 2009


The following commit has been merged in the webkit-1.1 branch:
commit b190d91908ae4641b1acff65ec00253147b42001
Author: mrowe at apple.com <mrowe at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Oct 17 02:31:42 2009 +0000

    Roll out r49717 as it broke the build.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@49726 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 6d439be..8c94bb6 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,15 +1,3 @@
-2009-10-16  Geoffrey Garen  <ggaren at apple.com>
-
-        Build fix: apparently we shouldn't export those symbols?
-
-        * JavaScriptCore.exp:
-
-2009-10-16  Geoffrey Garen  <ggaren at apple.com>
-
-        Build fix: export some symbols.
-
-        * JavaScriptCore.exp:
-
 2009-10-16  Oliver Hunt  <oliver at apple.com>
 
         Reviewed by Gavin Barraclough.
@@ -79,122 +67,6 @@
         * runtime/StringObjectThatMasqueradesAsUndefined.h:
         (JSC::StringObjectThatMasqueradesAsUndefined::createStructure):
 
-2009-10-16  Geoffrey Garen  <ggaren at apple.com>
-
-        Reviewed by Oliver Hunt.
-        
-        Fast for-in enumeration: Cache JSPropertyNameIterator; cache JSStrings
-        in JSPropertyNameIterator; inline more code.
-
-        1.024x as fast on SunSpider (fasta: 1.43x as fast).
-
-        * bytecode/CodeBlock.cpp:
-        (JSC::CodeBlock::dump):
-        * bytecode/Opcode.h:
-        * bytecompiler/BytecodeGenerator.cpp:
-        (JSC::BytecodeGenerator::emitGetPropertyNames):
-        (JSC::BytecodeGenerator::emitNextPropertyName):
-        * bytecompiler/BytecodeGenerator.h: Added a few extra operands to
-        op_get_pnames and op_next_pname so that we can track iteration state
-        in the register file instead of in the JSPropertyNameIterator. (To be
-        cacheable, the JSPropertyNameIterator must be stateless.)
-
-        * interpreter/Interpreter.cpp:
-        (JSC::Interpreter::tryCachePutByID):
-        (JSC::Interpreter::tryCacheGetByID): Updated for rename to
-        "normalizePrototypeChain" and removal of "isCacheable". 
-
-        (JSC::Interpreter::privateExecute): Updated for in-RegisterFile
-        iteration state tracking.
-
-        * jit/JIT.cpp:
-        (JSC::JIT::privateCompileMainPass):
-        * jit/JIT.h:
-        * jit/JITOpcodes.cpp:
-        (JSC::JIT::emit_op_get_pnames): Updated for in-RegisterFile
-        iteration state tracking.
-
-        (JSC::JIT::emit_op_next_pname): Inlined code generation for op_next_pname.
-
-        * jit/JITStubs.cpp:
-        (JSC::JITThunks::tryCachePutByID):
-        (JSC::JITThunks::tryCacheGetByID): Updated for rename to
-        "normalizePrototypeChain" and removal of "isCacheable". 
-
-        (JSC::DEFINE_STUB_FUNCTION):
-        * jit/JITStubs.h:
-        (JSC::): Added has_property and to_object stubs. Removed op_next_pname
-        stub, since has_property is all we need anymore.
-
-        * parser/Nodes.cpp:
-        (JSC::ForInNode::emitBytecode): Updated for in-RegisterFile
-        iteration state tracking.
-
-        * runtime/JSCell.h:
-        * runtime/JSObject.cpp:
-        (JSC::JSObject::getPropertyNames): Don't do caching at this layer
-        anymore, since we don't create a JSPropertyNameIterator at this layer.
-
-        * runtime/JSPropertyNameIterator.cpp:
-        (JSC::JSPropertyNameIterator::create): Do do caching at this layer.
-        (JSC::JSPropertyNameIterator::get):  Updated for in-RegisterFile
-        iteration state tracking.
-        (JSC::JSPropertyNameIterator::markChildren): Mark our JSStrings.
-
-        * runtime/JSPropertyNameIterator.h:
-        (JSC::JSPropertyNameIterator::size):
-        (JSC::JSPropertyNameIterator::setCachedStructure):
-        (JSC::JSPropertyNameIterator::cachedStructure):
-        (JSC::JSPropertyNameIterator::setCachedPrototypeChain):
-        (JSC::JSPropertyNameIterator::cachedPrototypeChain):
-        (JSC::JSPropertyNameIterator::JSPropertyNameIterator):
-        (JSC::Structure::setEnumerationCache): Don't store iteration state in
-        a JSPropertyNameIterator. Do cache a JSPropertyNameIterator in a
-        Structure.
-
-        * runtime/JSValue.h:
-        (JSC::asCell):
-        * runtime/MarkStack.h: Make those mischievous #include gods happy.
-
-        * runtime/ObjectConstructor.cpp:
-
-        * runtime/Operations.h:
-        (JSC::normalizePrototypeChain): Renamed countPrototypeChainEntriesAndCheckForProxies
-        to normalizePrototypeChain, since it changes dictionary prototypes to
-        non-dictionary objects.
-
-        * runtime/PropertyNameArray.cpp:
-        (JSC::PropertyNameArray::add):
-        * runtime/PropertyNameArray.h:
-        (JSC::PropertyNameArrayData::PropertyNameArrayData):
-        (JSC::PropertyNameArray::data):
-        (JSC::PropertyNameArray::size):
-        (JSC::PropertyNameArray::begin):
-        (JSC::PropertyNameArray::end): Simplified some code here to help with
-        current and future refactoring.
-
-        * runtime/Protect.h:
-        * runtime/Structure.cpp:
-        (JSC::Structure::~Structure):
-        (JSC::Structure::addPropertyWithoutTransition):
-        (JSC::Structure::removePropertyWithoutTransition): No need to clear
-        the enumeration cache with adding / removing properties without
-        transition. It is an error to add / remove properties without transition
-        once an object has been observed, and we can ASSERT to catch that.
-
-        * runtime/Structure.h:
-        (JSC::Structure::enumerationCache): Changed the enumeration cache to
-        hold a JSPropertyNameIterator.
-
-        * runtime/StructureChain.cpp:
-        * runtime/StructureChain.h:
-        (JSC::StructureChain::head): Removed StructureChain::isCacheable because
-        it was wrong-headed in two ways: (1) It gave up when a prototype was a
-        dictionary, but instead we want un-dictionary heavily accessed
-        prototypes; (2) It folded a test for hasDefaultGetPropertyNames() into
-        a generic test for "cacheable-ness", but hasDefaultGetPropertyNames()
-        is only releavant to for-in caching.
-
 2009-10-16  Steve Falkenburg  <sfalken at apple.com>
 
         Reviewed by Adam Roben.
diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp
index 18ca2ae..ef0054b 100644
--- a/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1015,18 +1015,16 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             break;
         }
         case op_get_pnames: {
-            int r0 = it[0].u.operand;
-            int r1 = it[1].u.operand;
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
             printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
-            it += OPCODE_LENGTH(op_get_pnames) - 1;
             break;
         }
         case op_next_pname: {
-            int dest = it[0].u.operand;
-            int iter = it[4].u.operand;
-            int offset = it[5].u.operand;
+            int dest = (++it)->u.operand;
+            int iter = (++it)->u.operand;
+            int offset = (++it)->u.operand;
             printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, location + offset);
-            it += OPCODE_LENGTH(op_next_pname) - 1;
             break;
         }
         case op_push_scope: {
diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h
index 8968252..c9196ce 100644
--- a/JavaScriptCore/bytecode/Opcode.h
+++ b/JavaScriptCore/bytecode/Opcode.h
@@ -152,8 +152,8 @@ namespace JSC {
         macro(op_strcat, 4) \
         macro(op_to_primitive, 3) \
         \
-        macro(op_get_pnames, 6) \
-        macro(op_next_pname, 7) \
+        macro(op_get_pnames, 3) \
+        macro(op_next_pname, 4) \
         \
         macro(op_push_scope, 2) \
         macro(op_pop_scope, 1) \
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 41b5c39..780a52e 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1794,28 +1794,12 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetSco
     return target;
 }
 
-RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
-{
-    size_t begin = instructions().size();
-
-    emitOpcode(op_get_pnames);
-    instructions().append(dst->index());
-    instructions().append(base->index());
-    instructions().append(i->index());
-    instructions().append(size->index());
-    instructions().append(breakTarget->bind(begin, instructions().size()));
-    return dst;
-}
-
-RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
+RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target)
 {
     size_t begin = instructions().size();
 
     emitOpcode(op_next_pname);
     instructions().append(dst->index());
-    instructions().append(base->index());
-    instructions().append(i->index());
-    instructions().append(size->index());
     instructions().append(iter->index());
     instructions().append(target->bind(begin, instructions().size()));
     return dst;
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 61de173..1a83ce9 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -312,8 +312,8 @@ namespace JSC {
         PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*);
         void emitSubroutineReturn(RegisterID* retAddrSrc);
 
-        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
-        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
+        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); }
+        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target);
 
         RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
         void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); }
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 53964ad..74b4eb1 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -938,20 +938,22 @@ NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock*
         return;
     }
 
+    StructureChain* protoChain = structure->prototypeChain(callFrame);
+    if (!protoChain->isCacheable()) {
+        vPC[0] = getOpcode(op_put_by_id_generic);
+        return;
+    }
+
     // Structure transition, cache transition info
     if (slot.type() == PutPropertySlot::NewProperty) {
         if (structure->isDictionary()) {
             vPC[0] = getOpcode(op_put_by_id_generic);
             return;
         }
-
-        // put_by_id_transition checks the prototype chain for setters.
-        normalizePrototypeChain(callFrame, baseCell);
-
         vPC[0] = getOpcode(op_put_by_id_transition);
         vPC[4] = structure->previousID();
         vPC[5] = structure;
-        vPC[6] = structure->prototypeChain(callFrame);
+        vPC[6] = protoChain;
         vPC[7] = slot.cachedOffset();
         codeBlock->refStructures(vPC);
         return;
@@ -1047,15 +1049,21 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
         return;
     }
 
-    size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase());
+    size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
     if (!count) {
         vPC[0] = getOpcode(op_get_by_id_generic);
         return;
     }
 
+    StructureChain* protoChain = structure->prototypeChain(callFrame);
+    if (!protoChain->isCacheable()) {
+        vPC[0] = getOpcode(op_get_by_id_generic);
+        return;
+    }
+
     vPC[0] = getOpcode(op_get_by_id_chain);
     vPC[4] = structure;
-    vPC[5] = structure->prototypeChain(callFrame);
+    vPC[5] = protoChain;
     vPC[6] = count;
     vPC[7] = slot.cachedOffset();
     codeBlock->refStructures(vPC);
@@ -3494,63 +3502,41 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         NEXT_INSTRUCTION();
     }
     DEFINE_OPCODE(op_get_pnames) {
-        /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
+        /* get_pnames dst(r) base(r)
 
            Creates a property name list for register base and puts it
-           in register dst, initializing i and size for iteration. If
-           base is undefined or null, jumps to breakTarget.
+           in register dst. This is not a true JavaScript value, just
+           a synthetic value used to keep the iteration state in a
+           register.
         */
         int dst = vPC[1].u.operand;
         int base = vPC[2].u.operand;
-        int i = vPC[3].u.operand;
-        int size = vPC[4].u.operand;
-        int breakTarget = vPC[5].u.operand;
 
-        JSValue v = callFrame->r(base).jsValue();
-        if (v.isUndefinedOrNull()) {
-            vPC += breakTarget;
-            NEXT_INSTRUCTION();
-        }
-
-        JSObject* o = v.toObject(callFrame);
-        Structure* structure = o->structure();
-        JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
-        if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
-            jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
-
-        callFrame->r(dst) = jsPropertyNameIterator;
-        callFrame->r(base) = JSValue(o);
-        callFrame->r(i) = Register::withInt(0);
-        callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
+        callFrame->r(dst) = JSPropertyNameIterator::create(callFrame, callFrame->r(base).jsValue());
         vPC += OPCODE_LENGTH(op_get_pnames);
         NEXT_INSTRUCTION();
     }
     DEFINE_OPCODE(op_next_pname) {
-        /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
+        /* next_pname dst(r) iter(r) target(offset)
 
-           Copies the next name from the property name list in
-           register iter to dst, then jumps to offset target. If there are no
-           names left, invalidates the iterator and continues to the next
+           Tries to copies the next name from property name list in
+           register iter. If there are names left, then copies one to
+           register dst, and jumps to offset target. If there are none
+           left, invalidates the iterator and continues to the next
            instruction.
         */
         int dst = vPC[1].u.operand;
-        int base = vPC[2].u.operand;
-        int i = vPC[3].u.operand;
-        int size = vPC[4].u.operand;
-        int iter = vPC[5].u.operand;
-        int target = vPC[6].u.operand;
+        int iter = vPC[2].u.operand;
+        int target = vPC[3].u.operand;
 
         JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
-        while (callFrame->r(i).i() != callFrame->r(size).i()) {
-            JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
-            callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
-            if (key) {
-                CHECK_FOR_TIMEOUT();
-                callFrame->r(dst) = key;
-                vPC += target;
-                NEXT_INSTRUCTION();
-            }
+        if (JSValue temp = it->next(callFrame)) {
+            CHECK_FOR_TIMEOUT();
+            callFrame->r(dst) = JSValue(temp);
+            vPC += target;
+            NEXT_INSTRUCTION();
         }
+        it->invalidate();
 
         vPC += OPCODE_LENGTH(op_next_pname);
         NEXT_INSTRUCTION();
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index fa0ac2e..5cead1d 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -202,6 +202,7 @@ void JIT::privateCompileMainPass()
         DEFINE_BINARY_OP(op_less)
         DEFINE_BINARY_OP(op_lesseq)
         DEFINE_BINARY_OP(op_urshift)
+        DEFINE_UNARY_OP(op_get_pnames)
         DEFINE_UNARY_OP(op_is_boolean)
         DEFINE_UNARY_OP(op_is_function)
         DEFINE_UNARY_OP(op_is_number)
@@ -240,7 +241,6 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_get_by_id)
         DEFINE_OP(op_get_by_val)
         DEFINE_OP(op_get_global_var)
-        DEFINE_OP(op_get_pnames)
         DEFINE_OP(op_get_scoped_var)
         DEFINE_OP(op_instanceof)
         DEFINE_OP(op_jeq_null)
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index 23e8883..0712743 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -713,7 +713,6 @@ namespace JSC {
         void emit_op_new_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
         void emit_op_new_regexp(Instruction*);
-        void emit_op_get_pnames(Instruction*);
         void emit_op_next_pname(Instruction*);
         void emit_op_not(Instruction*);
         void emit_op_nstricteq(Instruction*);
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index 59bc403..c793f90 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -33,7 +33,6 @@
 #include "JSArray.h"
 #include "JSCell.h"
 #include "JSFunction.h"
-#include "JSPropertyNameIterator.h"
 #include "LinkBuffer.h"
 
 namespace JSC {
@@ -1196,109 +1195,23 @@ void JIT::emit_op_throw(Instruction* currentInstruction)
 #endif
 }
 
-void JIT::emit_op_get_pnames(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    int base = currentInstruction[2].u.operand;
-    int i = currentInstruction[3].u.operand;
-    int size = currentInstruction[4].u.operand;
-    int breakTarget = currentInstruction[5].u.operand;
-
-    JumpList isNotObject;
-
-    emitLoad(base, regT1, regT0);
-    if (!m_codeBlock->isKnownNotImmediate(base))
-        isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
-    if (base != m_codeBlock->thisRegister()) {
-        loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-        isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
-    }
-
-    // We could inline the case where you have a valid cache, but
-    // this call doesn't seem to be hot.
-    Label isObject(this);
-    JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
-    getPnamesStubCall.addArgument(regT0);
-    getPnamesStubCall.call(dst);
-    load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
-    store32(Imm32(0), addressFor(i));
-    store32(regT3, addressFor(size));
-    Jump end = jump();
-
-    isNotObject.link(this);
-    addJump(branch32(Equal, regT1, Imm32(JSValue::NullTag)), breakTarget);
-    addJump(branch32(Equal, regT1, Imm32(JSValue::UndefinedTag)), breakTarget);
-    JITStubCall toObjectStubCall(this, cti_to_object);
-    toObjectStubCall.addArgument(regT1, regT0);
-    toObjectStubCall.call(base);
-    jump().linkTo(isObject, this);
-    
-    end.link(this);
-}
-
 void JIT::emit_op_next_pname(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
-    int base = currentInstruction[2].u.operand;
-    int i = currentInstruction[3].u.operand;
-    int size = currentInstruction[4].u.operand;
-    int it = currentInstruction[5].u.operand;
-    int target = currentInstruction[6].u.operand;
-    
-    JumpList callHasProperty;
-
-    Label begin(this);
-    load32(addressFor(i), regT0);
-    Jump end = branch32(Equal, regT0, addressFor(size));
-
-    // Grab key @ i
-    loadPtr(addressFor(it), regT1);
-    loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
-    load32(BaseIndex(regT2, regT0, TimesEight), regT2);
-    store32(Imm32(JSValue::CellTag), tagFor(dst));
-    store32(regT2, payloadFor(dst));
-
-    // Increment i
-    add32(Imm32(1), regT0);
-    store32(regT0, addressFor(i));
-
-    // Verify that i is valid:
-    loadPtr(addressFor(base), regT0);
+    int iter = currentInstruction[2].u.operand;
+    int target = currentInstruction[3].u.operand;
 
-    // Test base's structure
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-    callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
-
-    // Test base's prototype chain
-    loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
-    loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
-    addJump(branchTestPtr(Zero, Address(regT3)), target);
-
-    Label checkPrototype(this);
-    callHasProperty.append(branch32(Equal, Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::NullTag)));
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-    callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
-    addPtr(Imm32(sizeof(Structure*)), regT3);
-    branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
+    load32(Address(callFrameRegister, (iter * sizeof(Register))), regT0);
 
-    // Continue loop.
-    addJump(jump(), target);
-
-    // Slow case: Ask the object if i is valid.
-    callHasProperty.link(this);
-    loadPtr(addressFor(dst), regT1);
-    JITStubCall stubCall(this, cti_has_property);
+    JITStubCall stubCall(this, cti_op_next_pname);
     stubCall.addArgument(regT0);
-    stubCall.addArgument(regT1);
     stubCall.call();
 
-    // Test for valid key.
-    addJump(branchTest32(NonZero, regT0), target);
-    jump().linkTo(begin, this);
-
-    // End of loop.
-    end.link(this);
+    Jump endOfIter = branchTestPtr(Zero, regT0);
+    emitStore(dst, regT1, regT0);
+    map(m_bytecodeIndex + OPCODE_LENGTH(op_next_pname), dst, regT1, regT0);
+    addJump(jump(), target);
+    endOfIter.link(this);
 }
 
 void JIT::emit_op_push_scope(Instruction* currentInstruction)
@@ -2459,110 +2372,15 @@ void JIT::emit_op_throw(Instruction* currentInstruction)
 #endif
 }
 
-void JIT::emit_op_get_pnames(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    int base = currentInstruction[2].u.operand;
-    int i = currentInstruction[3].u.operand;
-    int size = currentInstruction[4].u.operand;
-    int breakTarget = currentInstruction[5].u.operand;
-
-    JumpList isNotObject;
-
-    emitGetVirtualRegister(base, regT0);
-    if (!m_codeBlock->isKnownNotImmediate(base))
-        isNotObject.append(emitJumpIfNotJSCell(regT0));
-    if (base != m_codeBlock->thisRegister()) {
-        loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-        isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
-    }
-
-    // We could inline the case where you have a valid cache, but
-    // this call doesn't seem to be hot.
-    Label isObject(this);
-    JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
-    getPnamesStubCall.addArgument(regT0);
-    getPnamesStubCall.call(dst);
-    load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
-    store32(Imm32(0), addressFor(i));
-    store32(regT3, addressFor(size));
-    Jump end = jump();
-
-    isNotObject.link(this);
-    move(regT0, regT1);
-    and32(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT1);
-    addJump(branch32(Equal, regT1, Imm32(JSImmediate::FullTagTypeNull)), breakTarget);
-
-    JITStubCall toObjectStubCall(this, cti_to_object);
-    toObjectStubCall.addArgument(regT0);
-    toObjectStubCall.call(base);
-    jump().linkTo(isObject, this);
-    
-    end.link(this);
-}
-
 void JIT::emit_op_next_pname(Instruction* currentInstruction)
 {
-    int dst = currentInstruction[1].u.operand;
-    int base = currentInstruction[2].u.operand;
-    int i = currentInstruction[3].u.operand;
-    int size = currentInstruction[4].u.operand;
-    int it = currentInstruction[5].u.operand;
-    int target = currentInstruction[6].u.operand;
-    
-    JumpList callHasProperty;
-
-    Label begin(this);
-    load32(addressFor(i), regT0);
-    Jump end = branch32(Equal, regT0, addressFor(size));
-
-    // Grab key @ i
-    loadPtr(addressFor(it), regT1);
-    loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
-    loadPtr(BaseIndex(regT2, regT0, TimesEight), regT2);
-    emitPutVirtualRegister(dst, regT2);
-
-    // Increment i
-    add32(Imm32(1), regT0);
-    store32(regT0, addressFor(i));
-
-    // Verify that i is valid:
-    emitGetVirtualRegister(base, regT0);
-
-    // Test base's structure
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-    callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
-
-    // Test base's prototype chain
-    loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
-    loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
-    addJump(branchTestPtr(Zero, Address(regT3)), target);
-
-    Label checkPrototype(this);
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2);
-    callHasProperty.append(emitJumpIfNotJSCell(regT2));
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
-    callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
-    addPtr(Imm32(sizeof(Structure*)), regT3);
-    branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
-
-    // Continue loop.
-    addJump(jump(), target);
-
-    // Slow case: Ask the object if i is valid.
-    callHasProperty.link(this);
-    emitGetVirtualRegister(dst, regT1);
-    JITStubCall stubCall(this, cti_has_property);
-    stubCall.addArgument(regT0);
-    stubCall.addArgument(regT1);
+    JITStubCall stubCall(this, cti_op_next_pname);
+    stubCall.addArgument(currentInstruction[2].u.operand, regT2);
     stubCall.call();
-
-    // Test for valid key.
-    addJump(branchTest32(NonZero, regT0), target);
-    jump().linkTo(begin, this);
-
-    // End of loop.
-    end.link(this);
+    Jump endOfIter = branchTestPtr(Zero, regT0);
+    emitPutVirtualRegister(currentInstruction[1].u.operand);
+    addJump(jump(), currentInstruction[3].u.operand);
+    endOfIter.link(this);
 }
 
 void JIT::emit_op_push_scope(Instruction* currentInstruction)
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 90ea807..ccdde37 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -700,15 +700,11 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co
 
     // Structure transition, cache transition info
     if (slot.type() == PutPropertySlot::NewProperty) {
-        if (structure->isDictionary()) {
+        StructureChain* prototypeChain = structure->prototypeChain(callFrame);
+        if (!prototypeChain->isCacheable() || structure->isDictionary()) {
             ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic));
             return;
         }
-
-        // put_by_id_transition checks the prototype chain for setters.
-        normalizePrototypeChain(callFrame, baseCell);
-
-        StructureChain* prototypeChain = structure->prototypeChain(callFrame);
         stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);
         JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress);
         return;
@@ -784,13 +780,17 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
         return;
     }
 
-    size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase());
+    size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
     if (!count) {
         stubInfo->accessType = access_get_by_id_generic;
         return;
     }
 
     StructureChain* prototypeChain = structure->prototypeChain(callFrame);
+    if (!prototypeChain->isCacheable()) {
+        ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
+        return;
+    }
     stubInfo->initGetByIdChain(structure, prototypeChain);
     JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress);
 }
@@ -1332,11 +1332,15 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
 
         if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
-    } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase())) {
+    } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) {
+        StructureChain* protoChain = structure->prototypeChain(callFrame);
+        if (!protoChain->isCacheable()) {
+            ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
+            return JSValue::encode(result);
+        }
+        
         int listIndex;
         PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
-
-        StructureChain* protoChain = structure->prototypeChain(callFrame);
         JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset());
 
         if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
@@ -2667,22 +2671,18 @@ DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    CallFrame* callFrame = stackFrame.callFrame;
-    JSObject* o = stackFrame.args[0].jsObject();
-    Structure* structure = o->structure();
-    JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
-    if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
-        jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
-    return jsPropertyNameIterator;
+    return JSPropertyNameIterator::create(stackFrame.callFrame, stackFrame.args[0].jsValue());
 }
 
-DEFINE_STUB_FUNCTION(int, has_property)
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_next_pname)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    JSObject* base = stackFrame.args[0].jsObject();
-    JSString* property = stackFrame.args[1].jsString();
-    return base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value()));
+    JSPropertyNameIterator* it = stackFrame.args[0].propertyNameIterator();
+    JSValue temp = it->next(stackFrame.callFrame);
+    if (!temp)
+        it->invalidate();
+    return JSValue::encode(temp);
 }
 
 DEFINE_STUB_FUNCTION(JSObject*, op_push_scope)
@@ -3023,14 +3023,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw)
     return JSValue::encode(exceptionValue);
 }
 
-DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-
-    CallFrame* callFrame = stackFrame.callFrame;
-    return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
-}
-
 } // namespace JSC
 
 #endif // ENABLE(JIT)
diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h
index ccbcd2a..daae043 100644
--- a/JavaScriptCore/jit/JITStubs.h
+++ b/JavaScriptCore/jit/JITStubs.h
@@ -63,7 +63,6 @@ namespace JSC {
         int32_t asInt32;
 
         JSValue jsValue() { return JSValue::decode(asEncodedJSValue); }
-        JSObject* jsObject() { return static_cast<JSObject*>(asPointer); }
         Identifier& identifier() { return *static_cast<Identifier*>(asPointer); }
         int32_t int32() { return asInt32; }
         CodeBlock* codeBlock() { return static_cast<CodeBlock*>(asPointer); }
@@ -286,6 +285,7 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_mod(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION);
+    EncodedJSValue JIT_STUB cti_op_next_pname(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_post_dec(STUB_ARGS_DECLARATION);
@@ -307,7 +307,6 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_typeof(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION);
-    EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_error(STUB_ARGS_DECLARATION);
@@ -333,7 +332,6 @@ extern "C" {
     int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS_DECLARATION);
     int JIT_STUB cti_op_loop_if_true(STUB_ARGS_DECLARATION);
     int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION);
-    int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION);
diff --git a/JavaScriptCore/parser/Nodes.cpp b/JavaScriptCore/parser/Nodes.cpp
index b1e317e..3bd318a 100644
--- a/JavaScriptCore/parser/Nodes.cpp
+++ b/JavaScriptCore/parser/Nodes.cpp
@@ -1468,16 +1468,14 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     if (!m_lexpr->isLocation())
         return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference.");
 
+    RefPtr<Label> continueTarget = generator.newLabel(); 
+
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
 
     if (m_init)
         generator.emitNode(generator.ignoredResult(), m_init);
-
-    RefPtr<RegisterID> base = generator.newTemporary();
-    generator.emitNode(base.get(), m_expr);
-    RefPtr<RegisterID> i = generator.newTemporary();
-    RefPtr<RegisterID> size = generator.newTemporary();
-    RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget());
+    RegisterID* forInBase = generator.emitNode(m_expr);
+    RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
     generator.emitJump(scope->continueTarget());
 
     RefPtr<Label> loopStart = generator.newLabel();
@@ -1519,7 +1517,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     generator.emitNode(dst, m_statement);
 
     generator.emitLabel(scope->continueTarget());
-    generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get());
+    generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get());
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
     generator.emitLabel(scope->breakTarget());
     return dst;
diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h
index 16a5131..63c58ac 100644
--- a/JavaScriptCore/runtime/JSCell.h
+++ b/JavaScriptCore/runtime/JSCell.h
@@ -112,6 +112,14 @@ namespace JSC {
         Structure* m_structure;
     };
 
+    // FIXME: We should deprecate this and just use JSValue::asCell() instead.
+    JSCell* asCell(JSValue);
+
+    inline JSCell* asCell(JSValue value)
+    {
+        return value.asCell();
+    }
+
     inline JSCell::JSCell(Structure* structure)
         : m_structure(structure)
     {
diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp
index 6932ded..b24af32 100644
--- a/JavaScriptCore/runtime/JSObject.cpp
+++ b/JavaScriptCore/runtime/JSObject.cpp
@@ -443,22 +443,45 @@ bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyNa
 
 void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
 {
-    getOwnPropertyNames(exec, propertyNames);
+    bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_structure->isDictionary());
 
-    if (prototype().isNull())
-        return;
+    if (shouldCache) {
+        if (PropertyNameArrayData* data = m_structure->enumerationCache()) {
+            if (data->cachedPrototypeChain() == m_structure->prototypeChain(exec)) {
+                propertyNames.setData(data);
+                return;
+            }
 
-    JSObject* prototype = asObject(this->prototype());
-    while(1) {
-        if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
-            prototype->getPropertyNames(exec, propertyNames);
-            break;
+            m_structure->clearEnumerationCache();
         }
-        prototype->getOwnPropertyNames(exec, propertyNames);
-        JSValue nextProto = prototype->prototype();
-        if (nextProto.isNull())
-            break;
-        prototype = asObject(nextProto);
+    }
+
+    getOwnPropertyNames(exec, propertyNames);
+
+    if (prototype().isObject()) {
+        propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly.
+        JSObject* prototype = asObject(this->prototype());
+        while(1) {
+            if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
+                prototype->getPropertyNames(exec, propertyNames);
+                break;
+            }
+            prototype->getOwnPropertyNames(exec, propertyNames);
+            JSValue nextProto = prototype->prototype();
+            if (!nextProto.isObject())
+                break;
+            prototype = asObject(nextProto);
+        }
+    }
+
+    if (shouldCache) {
+        StructureChain* protoChain = m_structure->prototypeChain(exec);
+        if (!protoChain->isCacheable())
+            return;
+        RefPtr<PropertyNameArrayData> data = propertyNames.data();
+        data->setCachedPrototypeChain(protoChain);
+        data->setCachedStructure(m_structure);
+        m_structure->setEnumerationCache(data.release());
     }
 }
 
diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
index 2cd9f75..e08a3d9 100644
--- a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -29,56 +29,26 @@
 #include "config.h"
 #include "JSPropertyNameIterator.h"
 
-#include "JSGlobalObject.h"
-
 namespace JSC {
 
 ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator);
 
-JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
+JSPropertyNameIterator::~JSPropertyNameIterator()
 {
-    ASSERT(!o->structure()->enumerationCache() ||
-            o->structure()->enumerationCache()->cachedStructure() != o->structure() ||
-            o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec));
-
-    PropertyNameArray propertyNames(exec);
-    o->getPropertyNames(exec, propertyNames);
-    JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data());
-
-    if (o->structure()->isDictionary())
-        return jsPropertyNameIterator;
-
-    if (o->structure()->typeInfo().overridesGetPropertyNames())
-        return jsPropertyNameIterator;
-    
-    size_t count = normalizePrototypeChain(exec, o);
-    StructureChain* structureChain = o->structure()->prototypeChain(exec);
-    RefPtr<Structure>* structure = structureChain->head();
-    for (size_t i = 0; i < count; ++i) {
-        if (structure[i]->typeInfo().overridesGetPropertyNames())
-            return jsPropertyNameIterator;
-    }
-
-    jsPropertyNameIterator->setCachedPrototypeChain(structureChain);
-    jsPropertyNameIterator->setCachedStructure(o->structure());
-    o->structure()->setEnumerationCache(jsPropertyNameIterator);
-    return jsPropertyNameIterator;
 }
 
-JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
+void JSPropertyNameIterator::markChildren(MarkStack& markStack)
 {
-    JSValue& identifier = m_jsStrings[i];
-    if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec))
-        return identifier;
-
-    if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value())))
-        return JSValue();
-    return identifier;
+    JSCell::markChildren(markStack);
+    if (m_object)
+        markStack.append(m_object);
 }
 
-void JSPropertyNameIterator::markChildren(MarkStack& markStack)
+void JSPropertyNameIterator::invalidate()
 {
-    markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues);
+    ASSERT(m_position == m_end);
+    m_object = 0;
+    m_data.clear();
 }
 
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 0559e0b..2b66d2b 100644
--- a/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -31,7 +31,6 @@
 
 #include "JSObject.h"
 #include "JSString.h"
-#include "Operations.h"
 #include "PropertyNameArray.h"
 
 namespace JSC {
@@ -40,51 +39,73 @@ namespace JSC {
     class JSObject;
 
     class JSPropertyNameIterator : public JSCell {
-        friend class JIT;
-
     public:
-        static JSPropertyNameIterator* create(ExecState*, JSObject*);
+        static JSPropertyNameIterator* create(ExecState*, JSValue);
+
+        virtual ~JSPropertyNameIterator();
+
+        virtual void markChildren(MarkStack&);
+
+        JSValue next(ExecState*);
+        void invalidate();
         
         static PassRefPtr<Structure> createStructure(JSValue prototype)
         {
             return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren));
         }
-
-        virtual void markChildren(MarkStack&);
-
-        JSValue get(ExecState*, JSObject*, size_t i);
-        size_t size() { return m_jsStringsSize; }
-
-        void setCachedStructure(Structure* structure) { m_cachedStructure = structure; }
-        Structure* cachedStructure() { return m_cachedStructure; }
-
-        void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
-        StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
-
     private:
-        JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData);
+        JSPropertyNameIterator(ExecState*);
+        JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData);
 
-        Structure* m_cachedStructure;
-        RefPtr<StructureChain> m_cachedPrototypeChain;
-        size_t m_jsStringsSize;
-        OwnArrayPtr<JSValue> m_jsStrings;
+        JSObject* m_object;
+        RefPtr<PropertyNameArrayData> m_data;
+        PropertyNameArrayData::const_iterator m_position;
+        PropertyNameArrayData::const_iterator m_end;
     };
 
-inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
+inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec)
     : JSCell(exec->globalData().propertyNameIteratorStructure.get())
-    , m_cachedStructure(0)
-    , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
-    , m_jsStrings(new JSValue[m_jsStringsSize])
+    , m_object(0)
+    , m_position(0)
+    , m_end(0)
 {
-    PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
-    for (size_t i = 0; i < m_jsStringsSize; ++i)
-        m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring());
 }
 
-inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache)
+inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData)
+    : JSCell(exec->globalData().propertyNameIteratorStructure.get())
+    , m_object(object)
+    , m_data(propertyNameArrayData)
+    , m_position(m_data->begin())
+    , m_end(m_data->end())
+{
+}
+
+inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v)
 {
-    ASSERT(!isDictionary());
-    m_enumerationCache = enumerationCache;
+    if (v.isUndefinedOrNull())
+        return new (exec) JSPropertyNameIterator(exec);
+
+    JSObject* o = v.toObject(exec);
+    PropertyNameArray propertyNames(exec);
+    o->getPropertyNames(exec, propertyNames);
+    return new (exec) JSPropertyNameIterator(exec, o, propertyNames.releaseData());
+}
+
+inline JSValue JSPropertyNameIterator::next(ExecState* exec)
+{
+    if (m_position == m_end)
+        return JSValue();
+
+    if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec))
+        return jsOwnedString(exec, (*m_position++).ustring());
+
+    do {
+        if (m_object->hasProperty(exec, *m_position))
+            return jsOwnedString(exec, (*m_position++).ustring());
+        m_position++;
+    } while (m_position != m_end);
+
+    return JSValue();
 }
 
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h
index 1063cdc..3c511d8 100644
--- a/JavaScriptCore/runtime/JSValue.h
+++ b/JavaScriptCore/runtime/JSValue.h
@@ -373,14 +373,6 @@ namespace JSC {
         return static_cast<uint32_t>(val);
     }
 
-    // FIXME: We should deprecate this and just use JSValue::asCell() instead.
-    JSCell* asCell(JSValue);
-
-    inline JSCell* asCell(JSValue value)
-    {
-        return value.asCell();
-    }
-
     ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
     {
         if (isInt32())
diff --git a/JavaScriptCore/runtime/MarkStack.h b/JavaScriptCore/runtime/MarkStack.h
index ea09f54..ba00057 100644
--- a/JavaScriptCore/runtime/MarkStack.h
+++ b/JavaScriptCore/runtime/MarkStack.h
@@ -47,7 +47,7 @@ namespace JSC {
         }
 
         ALWAYS_INLINE void append(JSValue);
-        void append(JSCell*);
+        ALWAYS_INLINE void append(JSCell*);
         
         ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues)
         {
diff --git a/JavaScriptCore/runtime/ObjectConstructor.cpp b/JavaScriptCore/runtime/ObjectConstructor.cpp
index 837d5a6..a456423 100644
--- a/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -125,7 +125,6 @@ JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec,
     return description;
 }
 
-// FIXME: Use the enumeration cache.
 JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
 {
     if (!args.at(0).isObject())
diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h
index 1aa68b3..5da9e38 100644
--- a/JavaScriptCore/runtime/Operations.h
+++ b/JavaScriptCore/runtime/Operations.h
@@ -224,15 +224,15 @@ namespace JSC {
         return jsAddSlowCase(callFrame, v1, v2);
     }
 
-    inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase)
+    inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot)
     {
-        JSCell* cell = asCell(base);
+        JSCell* cell = asCell(baseValue);
         size_t count = 0;
 
-        while (slotBase != cell) {
+        while (slot.slotBase() != cell) {
             JSValue v = cell->structure()->prototypeForLookup(callFrame);
 
-            // If we didn't find slotBase in base's prototype chain, then base
+            // If we didn't find slotBase in baseValue's prototype chain, then baseValue
             // must be a proxy for another object.
 
             if (v.isNull())
@@ -252,25 +252,6 @@ namespace JSC {
         return count;
     }
 
-    inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
-    {
-        size_t count = 0;
-        while (1) {
-            JSValue v = base->structure()->prototypeForLookup(callFrame);
-            if (v.isNull())
-                return count;
-
-            base = asCell(v);
-
-            // Since we're accessing a prototype in a loop, it's a good bet that it
-            // should not be treated as a dictionary.
-            if (base->structure()->isDictionary())
-                asObject(base)->setStructure(Structure::fromDictionaryTransition(base->structure()));
-
-            ++count;
-        }
-    }
-
     ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
     {
         ScopeChainIterator iter = scopeChain->begin();
diff --git a/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp
index c28b6a4..cff2605 100644
--- a/JavaScriptCore/runtime/PropertyNameArray.cpp
+++ b/JavaScriptCore/runtime/PropertyNameArray.cpp
@@ -47,7 +47,7 @@ void PropertyNameArray::add(UString::Rep* identifier)
             return;
     }
 
-    addKnownUnique(identifier);
+    m_data->propertyNameVector().append(Identifier(m_globalData, identifier));
 }
 
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/PropertyNameArray.h b/JavaScriptCore/runtime/PropertyNameArray.h
index 3dbcc9d..7d6edd0 100644
--- a/JavaScriptCore/runtime/PropertyNameArray.h
+++ b/JavaScriptCore/runtime/PropertyNameArray.h
@@ -24,7 +24,6 @@
 #include "CallFrame.h"
 #include "Identifier.h"
 #include <wtf/HashSet.h>
-#include <wtf/OwnArrayPtr.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
@@ -32,26 +31,39 @@ namespace JSC {
     class Structure;
     class StructureChain;
 
-    // FIXME: Rename to PropertyNameArray.
     class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
     public:
         typedef Vector<Identifier, 20> PropertyNameVector;
+        typedef PropertyNameVector::const_iterator const_iterator;
 
         static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
 
+        const_iterator begin() const { return m_propertyNameVector.begin(); }
+        const_iterator end() const { return m_propertyNameVector.end(); }
+
         PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
 
+        void setCachedStructure(Structure* structure) { m_cachedStructure = structure; }
+        Structure* cachedStructure() const { return m_cachedStructure; }
+
+        void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
+        StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
+
     private:
         PropertyNameArrayData()
+            : m_cachedStructure(0)
         {
         }
 
         PropertyNameVector m_propertyNameVector;
+        Structure* m_cachedStructure;
+        RefPtr<StructureChain> m_cachedPrototypeChain;
     };
 
-    // FIXME: Rename to PropertyNameArrayBuilder.
     class PropertyNameArray {
     public:
+        typedef PropertyNameArrayData::const_iterator const_iterator;
+
         PropertyNameArray(JSGlobalData* globalData)
             : m_data(PropertyNameArrayData::create())
             , m_globalData(globalData)
@@ -72,18 +84,21 @@ namespace JSC {
         void add(UString::Rep*);
         void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); }
 
+        size_t size() const { return m_data->propertyNameVector().size(); }
+
         Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
         const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
 
+        const_iterator begin() const { return m_data->begin(); }
+        const_iterator end() const { return m_data->end(); }
+
         void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
         PropertyNameArrayData* data() { return m_data.get(); }
+
         PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
 
-        // FIXME: Remove these functions.
-        typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
-        size_t size() const { return m_data->propertyNameVector().size(); }
-        const_iterator begin() const { return m_data->propertyNameVector().begin(); }
-        const_iterator end() const { return m_data->propertyNameVector().end(); }
+        void setShouldCache(bool shouldCache) { m_shouldCache = shouldCache; }
+        bool shouldCache() const { return m_shouldCache; }
 
     private:
         typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet;
diff --git a/JavaScriptCore/runtime/Protect.h b/JavaScriptCore/runtime/Protect.h
index a0d5443..224164d 100644
--- a/JavaScriptCore/runtime/Protect.h
+++ b/JavaScriptCore/runtime/Protect.h
@@ -22,8 +22,8 @@
 #ifndef Protect_h
 #define Protect_h
 
+#include "JSCell.h"
 #include "Collector.h"
-#include "JSValue.h"
 
 namespace JSC {
 
diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp
index a11050f..643a49a 100644
--- a/JavaScriptCore/runtime/Structure.cpp
+++ b/JavaScriptCore/runtime/Structure.cpp
@@ -28,10 +28,9 @@
 
 #include "Identifier.h"
 #include "JSObject.h"
-#include "JSPropertyNameIterator.h"
-#include "Lookup.h"
 #include "PropertyNameArray.h"
 #include "StructureChain.h"
+#include "Lookup.h"
 #include <wtf/RefCountedLeakCounter.h>
 #include <wtf/RefPtr.h>
 
@@ -160,9 +159,9 @@ Structure::~Structure()
             m_previous->table.removeAnonymousSlotTransition(m_anonymousSlotsInPrevious);
 
     }
-    
-    if (m_enumerationCache)
-        m_enumerationCache->setCachedStructure(0);
+
+    if (m_cachedPropertyNameArrayData)
+        m_cachedPropertyNameArrayData->setCachedStructure(0);
 
     if (m_propertyTable) {
         unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
@@ -283,6 +282,13 @@ void Structure::materializePropertyMap()
     }
 }
 
+void Structure::clearEnumerationCache()
+{
+    if (m_cachedPropertyNameArrayData)
+        m_cachedPropertyNameArrayData->setCachedStructure(0);
+    m_cachedPropertyNameArrayData.clear();
+}
+
 void Structure::growPropertyStorageCapacity()
 {
     if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
@@ -546,25 +552,25 @@ PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure)
 
 size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
 {
-    ASSERT(!m_enumerationCache);
     materializePropertyMapIfNecessary();
 
     m_isPinnedPropertyTable = true;
     size_t offset = put(propertyName, attributes, specificValue);
     if (propertyStorageSize() > propertyStorageCapacity())
         growPropertyStorageCapacity();
+    clearEnumerationCache();
     return offset;
 }
 
 size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName)
 {
     ASSERT(isUncacheableDictionary());
-    ASSERT(!m_enumerationCache);
 
     materializePropertyMapIfNecessary();
 
     m_isPinnedPropertyTable = true;
     size_t offset = remove(propertyName);
+    clearEnumerationCache();
     return offset;
 }
 
diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h
index 2496c1b..a027b1a 100644
--- a/JavaScriptCore/runtime/Structure.h
+++ b/JavaScriptCore/runtime/Structure.h
@@ -31,7 +31,6 @@
 #include "JSValue.h"
 #include "PropertyMapHashTable.h"
 #include "PropertyNameArray.h"
-#include "Protect.h"
 #include "StructureChain.h"
 #include "StructureTransitionTable.h"
 #include "JSTypeInfo.h"
@@ -124,8 +123,9 @@ namespace JSC {
         JSCell* specificValue() { return m_specificValueInPrevious; }
         void despecifyDictionaryFunction(const Identifier& propertyName);
 
-        void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
-        JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); }
+        void setEnumerationCache(PassRefPtr<PropertyNameArrayData> data) { m_cachedPropertyNameArrayData = data; }
+        PropertyNameArrayData* enumerationCache() { return m_cachedPropertyNameArrayData.get(); }
+        void clearEnumerationCache();
         void getEnumerablePropertyNames(PropertyNameArray&);
 
     private:
@@ -186,7 +186,7 @@ namespace JSC {
 
         StructureTransitionTable table;
 
-        ProtectedPtr<JSPropertyNameIterator> m_enumerationCache;
+        RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
 
         PropertyMapHashTable* m_propertyTable;
 
diff --git a/JavaScriptCore/runtime/StructureChain.cpp b/JavaScriptCore/runtime/StructureChain.cpp
index 085876c..0a9bc69 100644
--- a/JavaScriptCore/runtime/StructureChain.cpp
+++ b/JavaScriptCore/runtime/StructureChain.cpp
@@ -46,4 +46,18 @@ StructureChain::StructureChain(Structure* head)
     m_vector[i] = 0;
 }
 
+bool StructureChain::isCacheable() const
+{
+    uint32_t i = 0;
+    
+    while (m_vector[i]) {
+        // Both classes of dictionary structure may change arbitrarily so we can't cache them
+        if (m_vector[i]->isDictionary())
+            return false;
+        if (m_vector[i++]->typeInfo().overridesGetPropertyNames())
+            return false;
+    }
+    return true;
+}
+
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/StructureChain.h b/JavaScriptCore/runtime/StructureChain.h
index 816b66d..c48749d 100644
--- a/JavaScriptCore/runtime/StructureChain.h
+++ b/JavaScriptCore/runtime/StructureChain.h
@@ -36,11 +36,10 @@ namespace JSC {
     class Structure;
 
     class StructureChain : public RefCounted<StructureChain> {
-        friend class JIT;
-
     public:
         static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); }
         RefPtr<Structure>* head() { return m_vector.get(); }
+        bool isCacheable() const;
 
     private:
         StructureChain(Structure* head);
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 27622d5..b3430bb 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -34,12 +34,6 @@
         (WebCore::getExceptionCodeDescription):
         * dom/ExceptionCode.h:
 
-2009-10-16  Geoffrey Garen  <ggaren at apple.com>
-
-        Build fix: forgot to check in this #include.
-
-        * bridge/runtime_root.h:
-
 2009-10-16  Simon Fraser  <simon.fraser at apple.com>
 
         Reviewed by Dan Bernstein.
diff --git a/WebCore/bridge/runtime_root.h b/WebCore/bridge/runtime_root.h
index 1806bf5..eacbb57 100644
--- a/WebCore/bridge/runtime_root.h
+++ b/WebCore/bridge/runtime_root.h
@@ -31,7 +31,6 @@
 #endif
 #include <runtime/Protect.h>
 
-#include <wtf/Forward.h>
 #include <wtf/HashSet.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/RefCounted.h>

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list