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

oliver at apple.com oliver at apple.com
Wed Apr 7 23:14:03 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 0a4803c099d4da11d3f275eceb60c1352a315a3d
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Oct 29 01:25:02 2009 +0000

    Improve for..in enumeration performance
    https://bugs.webkit.org/show_bug.cgi?id=30887
    
    Reviewed by Geoff Garen.
    
    Improve indexing of an object with a for..in iterator by
    identifying cases where get_by_val is being used with a iterator
    as the subscript and replace it with a new get_by_pname
    bytecode.  get_by_pname then optimizes lookups that directly access
    the base object.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@50254 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index c0f5c88..0ddae8d 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,59 @@
+2009-10-28  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Geoff Garen.
+
+        Improve for..in enumeration performance
+        https://bugs.webkit.org/show_bug.cgi?id=30887
+
+        Improve indexing of an object with a for..in iterator by
+        identifying cases where get_by_val is being used with a iterator
+        as the subscript and replace it with a new get_by_pname
+        bytecode.  get_by_pname then optimizes lookups that directly access
+        the base object.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * bytecode/Opcode.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetByVal):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::pushOptimisedForIn):
+        (JSC::BytecodeGenerator::popOptimisedForIn):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::compileGetDirectOffset):
+        (JSC::JIT::emit_op_get_by_pname):
+        (JSC::JIT::emitSlow_op_get_by_pname):
+        * parser/Nodes.cpp:
+        (JSC::ForInNode::emitBytecode):
+        * runtime/JSObject.h:
+        * runtime/JSPropertyNameIterator.cpp:
+        (JSC::JSPropertyNameIterator::create):
+        * runtime/JSPropertyNameIterator.h:
+        (JSC::JSPropertyNameIterator::getOffset):
+        (JSC::JSPropertyNameIterator::JSPropertyNameIterator):
+        * runtime/JSValue.h:
+        (JSC::JSValue::):
+        * runtime/Structure.cpp:
+        (JSC::Structure::addPropertyTransition):
+        (JSC::Structure::changePrototypeTransition):
+        (JSC::Structure::despecifyFunctionTransition):
+        (JSC::Structure::addAnonymousSlotsTransition):
+        (JSC::Structure::getterSetterTransition):
+        (JSC::Structure::toDictionaryTransition):
+        (JSC::Structure::addPropertyWithoutTransition):
+          Track the existence (or not) of non-enumerable properties.
+        * runtime/Structure.h:
+        (JSC::Structure::propertyStorageCapacity):
+        (JSC::Structure::propertyStorageSize):
+        (JSC::Structure::hasNonEnumerableProperties):
+        (JSC::Structure::hasAnonymousSlots):
+
 2009-10-28  Dmitry Titov  <dimich at chromium.org>
 
         Not reviewed, attemp to fix Windows build.
diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp
index 18ca2ae..c915934 100644
--- a/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -824,6 +824,16 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
             break;
         }
+        case op_get_by_pname: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            int r4 = (++it)->u.operand;
+            int r5 = (++it)->u.operand;
+            printf("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str(), registerName(r4).c_str(), registerName(r5).c_str());
+            break;
+        }
         case op_put_by_val: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
@@ -1015,14 +1025,17 @@ 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;
-            printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
+            int r0 = it[1].u.operand;
+            int r1 = it[2].u.operand;
+            int r2 = it[3].u.operand;
+            int r3 = it[4].u.operand;
+            int offset = it[5].u.operand;
+            printf("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str(), offset, location + offset);
             it += OPCODE_LENGTH(op_get_pnames) - 1;
             break;
         }
         case op_next_pname: {
-            int dest = it[0].u.operand;
+            int dest = it[1].u.operand;
             int iter = it[4].u.operand;
             int offset = it[5].u.operand;
             printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, location + offset);
diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h
index 8968252..4facbef 100644
--- a/JavaScriptCore/bytecode/Opcode.h
+++ b/JavaScriptCore/bytecode/Opcode.h
@@ -113,6 +113,7 @@ namespace JSC {
         macro(op_put_by_id_generic, 8) \
         macro(op_del_by_id, 4) \
         macro(op_get_by_val, 4) \
+        macro(op_get_by_pname, 7) \
         macro(op_put_by_val, 4) \
         macro(op_del_by_val, 4) \
         macro(op_put_by_index, 4) \
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 41b5c39..04dae15 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1281,6 +1281,19 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base,
 
 RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
 {
+    for (size_t i = m_forInContextStack.size(); i > 0; i--) {
+        ForInContext& context = m_forInContextStack[i - 1];
+        if (context.propertyRegister == property) {
+            emitOpcode(op_get_by_pname);
+            instructions().append(dst->index());
+            instructions().append(base->index());
+            instructions().append(property->index());
+            instructions().append(context.expectedSubscriptRegister->index());
+            instructions().append(context.iterRegister->index());
+            instructions().append(context.indexRegister->index());
+            return dst;
+        }
+    }
     emitOpcode(op_get_by_val);
     instructions().append(dst->index());
     instructions().append(base->index());
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 61de173..4648fb5 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -61,6 +61,13 @@ namespace JSC {
         FinallyContext finallyContext;
     };
 
+    struct ForInContext {
+        RefPtr<RegisterID> expectedSubscriptRegister;
+        RefPtr<RegisterID> iterRegister;
+        RefPtr<RegisterID> indexRegister;
+        RefPtr<RegisterID> propertyRegister;
+    };
+
     class BytecodeGenerator : public FastAllocBase {
     public:
         typedef DeclarationStacks::VarStack VarStack;
@@ -331,6 +338,17 @@ namespace JSC {
         void pushFinallyContext(Label* target, RegisterID* returnAddrDst);
         void popFinallyContext();
 
+        void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
+        {
+            ForInContext context = { expectedBase, iter, index, propertyRegister };
+            m_forInContextStack.append(context);
+        }
+
+        void popOptimisedForIn()
+        {
+            m_forInContextStack.removeLast();
+        }
+
         LabelScope* breakTarget(const Identifier&);
         LabelScope* continueTarget(const Identifier&);
 
@@ -467,6 +485,7 @@ namespace JSC {
 
         Vector<ControlFlowContext> m_scopeContextStack;
         Vector<SwitchInfo> m_switchContextStack;
+        Vector<ForInContext> m_forInContextStack;
 
         int m_nextGlobalIndex;
         int m_nextParameterIndex;
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 53964ad..c77a0f1 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -2417,6 +2417,33 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         vPC += OPCODE_LENGTH(op_del_by_id);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_get_by_pname) {
+        int dst = vPC[1].u.operand;
+        int base = vPC[2].u.operand;
+        int property = vPC[3].u.operand;
+        int expected = vPC[4].u.operand;
+        int iter = vPC[5].u.operand;
+        int i = vPC[6].u.operand;
+
+        JSValue baseValue = callFrame->r(base).jsValue();
+        JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
+        JSValue subscript = callFrame->r(property).jsValue();
+        JSValue expectedSubscript = callFrame->r(expected).jsValue();
+        int index = callFrame->r(i).i() - 1;
+        JSValue result;
+        int offset = 0;
+        if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
+            callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset);
+            vPC += OPCODE_LENGTH(op_get_by_pname);
+            NEXT_INSTRUCTION();
+        }
+        Identifier propertyName(callFrame, subscript.toString(callFrame));
+        result = baseValue.get(callFrame, propertyName);
+        CHECK_FOR_EXCEPTION();
+        callFrame->r(dst) = result;
+        vPC += OPCODE_LENGTH(op_get_by_pname);
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_get_by_val) {
         /* get_by_val dst(r) base(r) property(r)
 
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index fa0ac2e..000e4b8 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -239,6 +239,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_eq_null)
         DEFINE_OP(op_get_by_id)
         DEFINE_OP(op_get_by_val)
+        DEFINE_OP(op_get_by_pname)
         DEFINE_OP(op_get_global_var)
         DEFINE_OP(op_get_pnames)
         DEFINE_OP(op_get_scoped_var)
@@ -385,6 +386,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_eq)
         DEFINE_SLOWCASE_OP(op_get_by_id)
         DEFINE_SLOWCASE_OP(op_get_by_val)
+        DEFINE_SLOWCASE_OP(op_get_by_pname)
         DEFINE_SLOWCASE_OP(op_instanceof)
         DEFINE_SLOWCASE_OP(op_jfalse)
         DEFINE_SLOWCASE_OP(op_jnless)
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index 63c5ce9..1452c0e 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -428,6 +428,7 @@ namespace JSC {
 #endif
         void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset);
         void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset);
+        void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset);
         void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, Structure* structure, size_t cachedOffset);
 
         // Arithmetic opcode helpers
@@ -529,6 +530,7 @@ namespace JSC {
 #endif
         void compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset);
         void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset);
+        void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch);
         void compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset);
 
 #if PLATFORM(X86_64)
@@ -683,6 +685,7 @@ namespace JSC {
         void emit_op_eq_null(Instruction*);
         void emit_op_get_by_id(Instruction*);
         void emit_op_get_by_val(Instruction*);
+        void emit_op_get_by_pname(Instruction*);
         void emit_op_get_global_var(Instruction*);
         void emit_op_get_scoped_var(Instruction*);
         void emit_op_init_arguments(Instruction*);
@@ -772,6 +775,7 @@ namespace JSC {
         void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&);
diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp
index d334af5..bf367a6 100644
--- a/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -33,6 +33,7 @@
 #include "JITStubCall.h"
 #include "JSArray.h"
 #include "JSFunction.h"
+#include "JSPropertyNameIterator.h"
 #include "Interpreter.h"
 #include "LinkBuffer.h"
 #include "RepatchBuffer.h"
@@ -934,6 +935,69 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
 
 #endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
 
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset)
+{
+    ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t));
+    ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t));
+    ASSERT(sizeof(JSValue) == 8);
+
+    Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity));
+    loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
+    loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+    Jump finishedLoad = jump();
+    notUsingInlineStorage.link(this);
+    loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
+    loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
+    loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+    finishedLoad.link(this);
+}
+
+void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
+{
+    unsigned dst = currentInstruction[1].u.operand;
+    unsigned base = currentInstruction[2].u.operand;
+    unsigned property = currentInstruction[3].u.operand;
+    unsigned expected = currentInstruction[4].u.operand;
+    unsigned iter = currentInstruction[5].u.operand;
+    unsigned i = currentInstruction[6].u.operand;
+
+    emitLoad2(property, regT1, regT0, base, regT3, regT2);
+    emitJumpSlowCaseIfNotJSCell(property, regT1);
+    addSlowCase(branchPtr(NotEqual, regT0, payloadFor(expected)));
+    // Property registers are now available as the property is known
+    emitJumpSlowCaseIfNotJSCell(base, regT3);
+    emitLoadPayload(iter, regT1);
+    
+    // Test base's structure
+    loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0);
+    addSlowCase(branchPtr(NotEqual, regT0, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
+    load32(addressFor(i), regT3);
+    sub32(Imm32(1), regT3);
+    addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
+    compileGetDirectOffset(regT2, regT1, regT0, regT0, regT3);    
+
+    emitStore(dst, regT1, regT0);
+    map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_pname), dst, regT1, regT0);
+}
+
+void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    unsigned dst = currentInstruction[1].u.operand;
+    unsigned base = currentInstruction[2].u.operand;
+    unsigned property = currentInstruction[3].u.operand;
+    
+    linkSlowCaseIfNotJSCell(iter, property);
+    linkSlowCase(iter);
+    linkSlowCaseIfNotJSCell(iter, base);
+    linkSlowCase(iter);
+    linkSlowCase(iter);
+    
+    JITStubCall stubCall(this, cti_op_get_by_val);
+    stubCall.addArgument(base);
+    stubCall.addArgument(property);
+    stubCall.call(dst);
+}
+
 #else // USE(JSVALUE32_64)
 
 void JIT::emit_op_get_by_val(Instruction* currentInstruction)
@@ -967,6 +1031,48 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     emitPutVirtualRegister(dst);
 }
 
+void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
+{
+    unsigned dst = currentInstruction[1].u.operand;
+    unsigned base = currentInstruction[2].u.operand;
+    unsigned property = currentInstruction[3].u.operand;
+    unsigned expected = currentInstruction[4].u.operand;
+    unsigned iter = currentInstruction[5].u.operand;
+    unsigned i = currentInstruction[6].u.operand;
+
+    emitGetVirtualRegister(property, regT0);
+    addSlowCase(branchPtr(NotEqual, regT0, addressFor(expected)));
+    emitGetVirtualRegisters(base, regT0, iter, regT1);
+    emitJumpSlowCaseIfNotJSCell(regT0, base);
+
+    // Test base's structure
+    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+    addSlowCase(branchPtr(NotEqual, regT2, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
+    load32(addressFor(i), regT3);
+    sub32(Imm32(1), regT3);
+    addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
+    compileGetDirectOffset(regT0, regT0, regT2, regT3, regT1);
+
+    emitPutVirtualRegister(dst, regT0);
+}
+
+void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    unsigned dst = currentInstruction[1].u.operand;
+    unsigned base = currentInstruction[2].u.operand;
+    unsigned property = currentInstruction[3].u.operand;
+
+    linkSlowCase(iter);
+    linkSlowCaseIfNotJSCell(iter, base);
+    linkSlowCase(iter);
+    linkSlowCase(iter);
+
+    JITStubCall stubCall(this, cti_op_get_by_val);
+    stubCall.addArgument(base, regT2);
+    stubCall.addArgument(property, regT2);
+    stubCall.call(dst);
+}
+
 void JIT::emit_op_put_by_val(Instruction* currentInstruction)
 {
     unsigned base = currentInstruction[1].u.operand;
@@ -1351,6 +1457,20 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res
     } 
 }
 
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch)
+{
+    ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t));
+    ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t));
+
+    Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity));
+    loadPtr(BaseIndex(base, offset, ScalePtr, OBJECT_OFFSETOF(JSObject, m_inlineStorage)), result);
+    Jump finishedLoad = jump();
+    notUsingInlineStorage.link(this);
+    loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), scratch);
+    loadPtr(BaseIndex(scratch, offset, ScalePtr, 0), result);    
+    finishedLoad.link(this);
+}
+
 void JIT::testPrototype(Structure* structure, JumpList& failureCases)
 {
     if (structure->m_prototype.isNull())
diff --git a/JavaScriptCore/parser/Nodes.cpp b/JavaScriptCore/parser/Nodes.cpp
index b1e317e..45009dc 100644
--- a/JavaScriptCore/parser/Nodes.cpp
+++ b/JavaScriptCore/parser/Nodes.cpp
@@ -1477,6 +1477,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     generator.emitNode(base.get(), m_expr);
     RefPtr<RegisterID> i = generator.newTemporary();
     RefPtr<RegisterID> size = generator.newTemporary();
+    RefPtr<RegisterID> expectedSubscript;
     RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget());
     generator.emitJump(scope->continueTarget());
 
@@ -1484,6 +1485,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     generator.emitLabel(loopStart.get());
 
     RegisterID* propertyName;
+    bool optimizedForinAccess = false;
     if (m_lexpr->isResolveNode()) {
         const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
         propertyName = generator.registerFor(ident);
@@ -1494,6 +1496,10 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
 
             generator.emitExpressionInfo(divot(), startOffset(), endOffset());
             generator.emitPutById(base, ident, propertyName);
+        } else {
+            expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
+            generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
+            optimizedForinAccess = true;
         }
     } else if (m_lexpr->isDotAccessorNode()) {
         DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
@@ -1518,6 +1524,9 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
 
     generator.emitNode(dst, m_statement);
 
+    if (optimizedForinAccess)
+        generator.popOptimisedForIn();
+
     generator.emitLabel(scope->continueTarget());
     generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get());
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h
index 1dbab94..5a89c40 100644
--- a/JavaScriptCore/runtime/JSObject.h
+++ b/JavaScriptCore/runtime/JSObject.h
@@ -202,8 +202,8 @@ namespace JSC {
         void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
         bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
 
-        static const size_t inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
-        static const size_t nonInlineBaseStorageCapacity = 16;
+        static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
+        static const unsigned nonInlineBaseStorageCapacity = 16;
 
         static PassRefPtr<Structure> createStructure(JSValue prototype)
         {
diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
index 2cd9f75..6fd0344 100644
--- a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -43,7 +43,12 @@ JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject
 
     PropertyNameArray propertyNames(exec);
     o->getPropertyNames(exec, propertyNames);
-    JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data());
+    size_t numCacheableSlots = 0;
+    if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasAnonymousSlots() &&
+        !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames())
+        numCacheableSlots = o->structure()->propertyStorageSize();
+
+    JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots);
 
     if (o->structure()->isDictionary())
         return jsPropertyNameIterator;
diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 14d882b..529ae8b 100644
--- a/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -54,6 +54,14 @@ namespace JSC {
 
         virtual void markChildren(MarkStack&);
 
+        bool getOffset(size_t i, int& offset)
+        {
+            if (i >= m_numCacheableSlots)
+                return false;
+            offset = i;
+            return true;
+        }
+
         JSValue get(ExecState*, JSObject*, size_t i);
         size_t size() { return m_jsStringsSize; }
 
@@ -64,17 +72,19 @@ namespace JSC {
         StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
 
     private:
-        JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData);
+        JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot);
 
         Structure* m_cachedStructure;
         RefPtr<StructureChain> m_cachedPrototypeChain;
-        size_t m_jsStringsSize;
+        uint32_t m_numCacheableSlots;
+        uint32_t m_jsStringsSize;
         OwnArrayPtr<JSValue> m_jsStrings;
     };
 
-inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
+inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
     : JSCell(exec->globalData().propertyNameIteratorStructure.get())
     , m_cachedStructure(0)
+    , m_numCacheableSlots(numCacheableSlots)
     , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
     , m_jsStrings(new JSValue[m_jsStringsSize])
 {
diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp
index a11050f..65b62f9 100644
--- a/JavaScriptCore/runtime/Structure.cpp
+++ b/JavaScriptCore/runtime/Structure.cpp
@@ -375,6 +375,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
     transition->m_specificValueInPrevious = specificValue;
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
 
     if (structure->m_propertyTable) {
         if (structure->m_isPinnedPropertyTable)
@@ -417,6 +418,7 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure,
 
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
 
     // Don't set m_offset, as one can not transition to this.
 
@@ -433,6 +435,7 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur
 
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
 
     // Don't set m_offset, as one can not transition to this.
 
@@ -464,6 +467,7 @@ PassRefPtr<Structure> Structure::addAnonymousSlotsTransition(Structure* structur
     transition->m_specificValueInPrevious = 0;
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
 
     if (structure->m_propertyTable) {
         if (structure->m_isPinnedPropertyTable)
@@ -492,6 +496,7 @@ PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
     RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
 
     // Don't set m_offset, as one can not transition to this.
 
@@ -510,6 +515,7 @@ PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, Di
     transition->m_dictionaryKind = kind;
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
     
     structure->materializePropertyMapIfNecessary();
     transition->m_propertyTable = structure->copyPropertyTable();
@@ -550,6 +556,9 @@ size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, u
     materializePropertyMapIfNecessary();
 
     m_isPinnedPropertyTable = true;
+    if (attributes & DontEnum)
+        m_hasNonEnumerableProperties = true;
+
     size_t offset = put(propertyName, attributes, specificValue);
     if (propertyStorageSize() > propertyStorageCapacity())
         growPropertyStorageCapacity();
diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h
index 2496c1b..f355c53 100644
--- a/JavaScriptCore/runtime/Structure.h
+++ b/JavaScriptCore/runtime/Structure.h
@@ -95,8 +95,8 @@ namespace JSC {
         Structure* previousID() const { return m_previous.get(); }
 
         void growPropertyStorageCapacity();
-        size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
-        size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
+        unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
+        unsigned propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
         bool isUsingInlineStorage() const;
 
         size_t get(const Identifier& propertyName);
@@ -119,6 +119,10 @@ namespace JSC {
         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
 
+        bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
+
+        bool hasAnonymousSlots() const { return m_propertyTable && m_propertyTable->anonymousSlotCount; }
+        
         bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
 
         JSCell* specificValue() { return m_specificValueInPrevious; }
@@ -190,12 +194,13 @@ namespace JSC {
 
         PropertyMapHashTable* m_propertyTable;
 
-        size_t m_propertyStorageCapacity;
+        uint32_t m_propertyStorageCapacity;
         signed char m_offset;
 
         unsigned m_dictionaryKind : 2;
         bool m_isPinnedPropertyTable : 1;
         bool m_hasGetterSetterProperties : 1;
+        bool m_hasNonEnumerableProperties : 1;
 #if COMPILER(WINSCW)
         // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
         // bitfield, when used as argument in make_pair() function calls in structure.ccp.

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list