Changeset 49717 in webkit


Ignore:
Timestamp:
Oct 16, 2009, 5:28:19 PM (16 years ago)
Author:
[email protected]
Message:

Fast for-in enumeration: Cache JSPropertyNameIterator; cache JSStrings
in JSPropertyNameIterator; inline more code.

Patch by Geoffrey Garen <[email protected]> on 2009-10-16
Reviewed by Oliver Hunt.

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.

Location:
trunk/JavaScriptCore
Files:
27 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r49705 r49717  
     12009-10-16  Geoffrey Garen  <[email protected]>
     2
     3        Reviewed by Oliver Hunt.
     4       
     5        Fast for-in enumeration: Cache JSPropertyNameIterator; cache JSStrings
     6        in JSPropertyNameIterator; inline more code.
     7
     8        1.024x as fast on SunSpider (fasta: 1.43x as fast).
     9
     10        * bytecode/CodeBlock.cpp:
     11        (JSC::CodeBlock::dump):
     12        * bytecode/Opcode.h:
     13        * bytecompiler/BytecodeGenerator.cpp:
     14        (JSC::BytecodeGenerator::emitGetPropertyNames):
     15        (JSC::BytecodeGenerator::emitNextPropertyName):
     16        * bytecompiler/BytecodeGenerator.h: Added a few extra operands to
     17        op_get_pnames and op_next_pname so that we can track iteration state
     18        in the register file instead of in the JSPropertyNameIterator. (To be
     19        cacheable, the JSPropertyNameIterator must be stateless.)
     20
     21        * interpreter/Interpreter.cpp:
     22        (JSC::Interpreter::tryCachePutByID):
     23        (JSC::Interpreter::tryCacheGetByID): Updated for rename to
     24        "normalizePrototypeChain" and removal of "isCacheable".
     25
     26        (JSC::Interpreter::privateExecute): Updated for in-RegisterFile
     27        iteration state tracking.
     28
     29        * jit/JIT.cpp:
     30        (JSC::JIT::privateCompileMainPass):
     31        * jit/JIT.h:
     32        * jit/JITOpcodes.cpp:
     33        (JSC::JIT::emit_op_get_pnames): Updated for in-RegisterFile
     34        iteration state tracking.
     35
     36        (JSC::JIT::emit_op_next_pname): Inlined code generation for op_next_pname.
     37
     38        * jit/JITStubs.cpp:
     39        (JSC::JITThunks::tryCachePutByID):
     40        (JSC::JITThunks::tryCacheGetByID): Updated for rename to
     41        "normalizePrototypeChain" and removal of "isCacheable".
     42
     43        (JSC::DEFINE_STUB_FUNCTION):
     44        * jit/JITStubs.h:
     45        (JSC::): Added has_property and to_object stubs. Removed op_next_pname
     46        stub, since has_property is all we need anymore.
     47
     48        * parser/Nodes.cpp:
     49        (JSC::ForInNode::emitBytecode): Updated for in-RegisterFile
     50        iteration state tracking.
     51
     52        * runtime/JSCell.h:
     53        * runtime/JSObject.cpp:
     54        (JSC::JSObject::getPropertyNames): Don't do caching at this layer
     55        anymore, since we don't create a JSPropertyNameIterator at this layer.
     56
     57        * runtime/JSPropertyNameIterator.cpp:
     58        (JSC::JSPropertyNameIterator::create): Do do caching at this layer.
     59        (JSC::JSPropertyNameIterator::get):  Updated for in-RegisterFile
     60        iteration state tracking.
     61        (JSC::JSPropertyNameIterator::markChildren): Mark our JSStrings.
     62
     63        * runtime/JSPropertyNameIterator.h:
     64        (JSC::JSPropertyNameIterator::size):
     65        (JSC::JSPropertyNameIterator::setCachedStructure):
     66        (JSC::JSPropertyNameIterator::cachedStructure):
     67        (JSC::JSPropertyNameIterator::setCachedPrototypeChain):
     68        (JSC::JSPropertyNameIterator::cachedPrototypeChain):
     69        (JSC::JSPropertyNameIterator::JSPropertyNameIterator):
     70        (JSC::Structure::setEnumerationCache): Don't store iteration state in
     71        a JSPropertyNameIterator. Do cache a JSPropertyNameIterator in a
     72        Structure.
     73
     74        * runtime/JSValue.h:
     75        (JSC::asCell):
     76        * runtime/MarkStack.h: Make those mischievous #include gods happy.
     77
     78        * runtime/ObjectConstructor.cpp:
     79
     80        * runtime/Operations.h:
     81        (JSC::normalizePrototypeChain): Renamed countPrototypeChainEntriesAndCheckForProxies
     82        to normalizePrototypeChain, since it changes dictionary prototypes to
     83        non-dictionary objects.
     84
     85        * runtime/PropertyNameArray.cpp:
     86        (JSC::PropertyNameArray::add):
     87        * runtime/PropertyNameArray.h:
     88        (JSC::PropertyNameArrayData::PropertyNameArrayData):
     89        (JSC::PropertyNameArray::data):
     90        (JSC::PropertyNameArray::size):
     91        (JSC::PropertyNameArray::begin):
     92        (JSC::PropertyNameArray::end): Simplified some code here to help with
     93        current and future refactoring.
     94
     95        * runtime/Protect.h:
     96        * runtime/Structure.cpp:
     97        (JSC::Structure::~Structure):
     98        (JSC::Structure::addPropertyWithoutTransition):
     99        (JSC::Structure::removePropertyWithoutTransition): No need to clear
     100        the enumeration cache with adding / removing properties without
     101        transition. It is an error to add / remove properties without transition
     102        once an object has been observed, and we can ASSERT to catch that.
     103
     104        * runtime/Structure.h:
     105        (JSC::Structure::enumerationCache): Changed the enumeration cache to
     106        hold a JSPropertyNameIterator.
     107
     108        * runtime/StructureChain.cpp:
     109        * runtime/StructureChain.h:
     110        (JSC::StructureChain::head): Removed StructureChain::isCacheable because
     111        it was wrong-headed in two ways: (1) It gave up when a prototype was a
     112        dictionary, but instead we want un-dictionary heavily accessed
     113        prototypes; (2) It folded a test for hasDefaultGetPropertyNames() into
     114        a generic test for "cacheable-ness", but hasDefaultGetPropertyNames()
     115        is only releavant to for-in caching.
     116
    11172009-10-16  Steve Falkenburg  <[email protected]>
    2118
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r49409 r49717  
    10161016        }
    10171017        case op_get_pnames: {
    1018             int r0 = (++it)->u.operand;
    1019             int r1 = (++it)->u.operand;
     1018            int r0 = it[0].u.operand;
     1019            int r1 = it[1].u.operand;
    10201020            printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
     1021            it += OPCODE_LENGTH(op_get_pnames) - 1;
    10211022            break;
    10221023        }
    10231024        case op_next_pname: {
    1024             int dest = (++it)->u.operand;
    1025             int iter = (++it)->u.operand;
    1026             int offset = (++it)->u.operand;
     1025            int dest = it[0].u.operand;
     1026            int iter = it[4].u.operand;
     1027            int offset = it[5].u.operand;
    10271028            printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, location + offset);
     1029            it += OPCODE_LENGTH(op_next_pname) - 1;
    10281030            break;
    10291031        }
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r46598 r49717  
    153153        macro(op_to_primitive, 3) \
    154154        \
    155         macro(op_get_pnames, 3) \
    156         macro(op_next_pname, 4) \
     155        macro(op_get_pnames, 6) \
     156        macro(op_next_pname, 7) \
    157157        \
    158158        macro(op_push_scope, 2) \
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r49409 r49717  
    17951795}
    17961796
    1797 RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target)
     1797RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
    17981798{
    17991799    size_t begin = instructions().size();
    18001800
     1801    emitOpcode(op_get_pnames);
     1802    instructions().append(dst->index());
     1803    instructions().append(base->index());
     1804    instructions().append(i->index());
     1805    instructions().append(size->index());
     1806    instructions().append(breakTarget->bind(begin, instructions().size()));
     1807    return dst;
     1808}
     1809
     1810RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
     1811{
     1812    size_t begin = instructions().size();
     1813
    18011814    emitOpcode(op_next_pname);
    18021815    instructions().append(dst->index());
     1816    instructions().append(base->index());
     1817    instructions().append(i->index());
     1818    instructions().append(size->index());
    18031819    instructions().append(iter->index());
    18041820    instructions().append(target->bind(begin, instructions().size()));
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r48662 r49717  
    313313        void emitSubroutineReturn(RegisterID* retAddrSrc);
    314314
    315         RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); }
    316         RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target);
     315        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
     316        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
    317317
    318318        RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r49409 r49717  
    939939    }
    940940
    941     StructureChain* protoChain = structure->prototypeChain(callFrame);
    942     if (!protoChain->isCacheable()) {
    943         vPC[0] = getOpcode(op_put_by_id_generic);
    944         return;
    945     }
    946 
    947941    // Structure transition, cache transition info
    948942    if (slot.type() == PutPropertySlot::NewProperty) {
     
    951945            return;
    952946        }
     947
     948        // put_by_id_transition checks the prototype chain for setters.
     949        normalizePrototypeChain(callFrame, baseCell);
     950
    953951        vPC[0] = getOpcode(op_put_by_id_transition);
    954952        vPC[4] = structure->previousID();
    955953        vPC[5] = structure;
    956         vPC[6] = protoChain;
     954        vPC[6] = structure->prototypeChain(callFrame);
    957955        vPC[7] = slot.cachedOffset();
    958956        codeBlock->refStructures(vPC);
     
    10501048    }
    10511049
    1052     size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
     1050    size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase());
    10531051    if (!count) {
    10541052        vPC[0] = getOpcode(op_get_by_id_generic);
     
    10561054    }
    10571055
    1058     StructureChain* protoChain = structure->prototypeChain(callFrame);
    1059     if (!protoChain->isCacheable()) {
    1060         vPC[0] = getOpcode(op_get_by_id_generic);
    1061         return;
    1062     }
    1063 
    10641056    vPC[0] = getOpcode(op_get_by_id_chain);
    10651057    vPC[4] = structure;
    1066     vPC[5] = protoChain;
     1058    vPC[5] = structure->prototypeChain(callFrame);
    10671059    vPC[6] = count;
    10681060    vPC[7] = slot.cachedOffset();
     
    35033495    }
    35043496    DEFINE_OPCODE(op_get_pnames) {
    3505         /* get_pnames dst(r) base(r)
     3497        /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
    35063498
    35073499           Creates a property name list for register base and puts it
    3508            in register dst. This is not a true JavaScript value, just
    3509            a synthetic value used to keep the iteration state in a
    3510            register.
     3500           in register dst, initializing i and size for iteration. If
     3501           base is undefined or null, jumps to breakTarget.
    35113502        */
    35123503        int dst = vPC[1].u.operand;
    35133504        int base = vPC[2].u.operand;
    3514 
    3515         callFrame->r(dst) = JSPropertyNameIterator::create(callFrame, callFrame->r(base).jsValue());
     3505        int i = vPC[3].u.operand;
     3506        int size = vPC[4].u.operand;
     3507        int breakTarget = vPC[5].u.operand;
     3508
     3509        JSValue v = callFrame->r(base).jsValue();
     3510        if (v.isUndefinedOrNull()) {
     3511            vPC += breakTarget;
     3512            NEXT_INSTRUCTION();
     3513        }
     3514
     3515        JSObject* o = v.toObject(callFrame);
     3516        Structure* structure = o->structure();
     3517        JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
     3518        if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
     3519            jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
     3520
     3521        callFrame->r(dst) = jsPropertyNameIterator;
     3522        callFrame->r(base) = JSValue(o);
     3523        callFrame->r(i) = Register::withInt(0);
     3524        callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
    35163525        vPC += OPCODE_LENGTH(op_get_pnames);
    35173526        NEXT_INSTRUCTION();
    35183527    }
    35193528    DEFINE_OPCODE(op_next_pname) {
    3520         /* next_pname dst(r) iter(r) target(offset)
    3521 
    3522            Tries to copies the next name from property name list in
    3523            register iter. If there are names left, then copies one to
    3524            register dst, and jumps to offset target. If there are none
    3525            left, invalidates the iterator and continues to the next
     3529        /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
     3530
     3531           Copies the next name from the property name list in
     3532           register iter to dst, then jumps to offset target. If there are no
     3533           names left, invalidates the iterator and continues to the next
    35263534           instruction.
    35273535        */
    35283536        int dst = vPC[1].u.operand;
    3529         int iter = vPC[2].u.operand;
    3530         int target = vPC[3].u.operand;
     3537        int base = vPC[2].u.operand;
     3538        int i = vPC[3].u.operand;
     3539        int size = vPC[4].u.operand;
     3540        int iter = vPC[5].u.operand;
     3541        int target = vPC[6].u.operand;
    35313542
    35323543        JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
    3533         if (JSValue temp = it->next(callFrame)) {
    3534             CHECK_FOR_TIMEOUT();
    3535             callFrame->r(dst) = JSValue(temp);
    3536             vPC += target;
    3537             NEXT_INSTRUCTION();
    3538         }
    3539         it->invalidate();
     3544        while (callFrame->r(i).i() != callFrame->r(size).i()) {
     3545            JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
     3546            callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
     3547            if (key) {
     3548                CHECK_FOR_TIMEOUT();
     3549                callFrame->r(dst) = key;
     3550                vPC += target;
     3551                NEXT_INSTRUCTION();
     3552            }
     3553        }
    35403554
    35413555        vPC += OPCODE_LENGTH(op_next_pname);
  • trunk/JavaScriptCore/jit/JIT.cpp

    r49409 r49717  
    203203        DEFINE_BINARY_OP(op_lesseq)
    204204        DEFINE_BINARY_OP(op_urshift)
    205         DEFINE_UNARY_OP(op_get_pnames)
    206205        DEFINE_UNARY_OP(op_is_boolean)
    207206        DEFINE_UNARY_OP(op_is_function)
     
    242241        DEFINE_OP(op_get_by_val)
    243242        DEFINE_OP(op_get_global_var)
     243        DEFINE_OP(op_get_pnames)
    244244        DEFINE_OP(op_get_scoped_var)
    245245        DEFINE_OP(op_instanceof)
  • trunk/JavaScriptCore/jit/JIT.h

    r48920 r49717  
    714714        void emit_op_new_object(Instruction*);
    715715        void emit_op_new_regexp(Instruction*);
     716        void emit_op_get_pnames(Instruction*);
    716717        void emit_op_next_pname(Instruction*);
    717718        void emit_op_not(Instruction*);
  • trunk/JavaScriptCore/jit/JITOpcodes.cpp

    r49509 r49717  
    3434#include "JSCell.h"
    3535#include "JSFunction.h"
     36#include "JSPropertyNameIterator.h"
    3637#include "LinkBuffer.h"
    3738
     
    11961197}
    11971198
     1199void JIT::emit_op_get_pnames(Instruction* currentInstruction)
     1200{
     1201    int dst = currentInstruction[1].u.operand;
     1202    int base = currentInstruction[2].u.operand;
     1203    int i = currentInstruction[3].u.operand;
     1204    int size = currentInstruction[4].u.operand;
     1205    int breakTarget = currentInstruction[5].u.operand;
     1206
     1207    JumpList isNotObject;
     1208
     1209    emitLoad(base, regT1, regT0);
     1210    if (!m_codeBlock->isKnownNotImmediate(base))
     1211        isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     1212    if (base != m_codeBlock->thisRegister()) {
     1213        loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     1214        isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
     1215    }
     1216
     1217    // We could inline the case where you have a valid cache, but
     1218    // this call doesn't seem to be hot.
     1219    Label isObject(this);
     1220    JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
     1221    getPnamesStubCall.addArgument(regT0);
     1222    getPnamesStubCall.call(dst);
     1223    load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
     1224    store32(Imm32(0), addressFor(i));
     1225    store32(regT3, addressFor(size));
     1226    Jump end = jump();
     1227
     1228    isNotObject.link(this);
     1229    addJump(branch32(Equal, regT1, Imm32(JSValue::NullTag)), breakTarget);
     1230    addJump(branch32(Equal, regT1, Imm32(JSValue::UndefinedTag)), breakTarget);
     1231    JITStubCall toObjectStubCall(this, cti_to_object);
     1232    toObjectStubCall.addArgument(regT1, regT0);
     1233    toObjectStubCall.call(base);
     1234    jump().linkTo(isObject, this);
     1235   
     1236    end.link(this);
     1237}
     1238
    11981239void JIT::emit_op_next_pname(Instruction* currentInstruction)
    11991240{
    12001241    int dst = currentInstruction[1].u.operand;
    1201     int iter = currentInstruction[2].u.operand;
    1202     int target = currentInstruction[3].u.operand;
    1203 
    1204     load32(Address(callFrameRegister, (iter * sizeof(Register))), regT0);
    1205 
    1206     JITStubCall stubCall(this, cti_op_next_pname);
     1242    int base = currentInstruction[2].u.operand;
     1243    int i = currentInstruction[3].u.operand;
     1244    int size = currentInstruction[4].u.operand;
     1245    int it = currentInstruction[5].u.operand;
     1246    int target = currentInstruction[6].u.operand;
     1247   
     1248    JumpList callHasProperty;
     1249
     1250    Label begin(this);
     1251    load32(addressFor(i), regT0);
     1252    Jump end = branch32(Equal, regT0, addressFor(size));
     1253
     1254    // Grab key @ i
     1255    loadPtr(addressFor(it), regT1);
     1256    loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
     1257    load32(BaseIndex(regT2, regT0, TimesEight), regT2);
     1258    store32(Imm32(JSValue::CellTag), tagFor(dst));
     1259    store32(regT2, payloadFor(dst));
     1260
     1261    // Increment i
     1262    add32(Imm32(1), regT0);
     1263    store32(regT0, addressFor(i));
     1264
     1265    // Verify that i is valid:
     1266    loadPtr(addressFor(base), regT0);
     1267
     1268    // Test base's structure
     1269    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     1270    callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
     1271
     1272    // Test base's prototype chain
     1273    loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
     1274    loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
     1275    addJump(branchTestPtr(Zero, Address(regT3)), target);
     1276
     1277    Label checkPrototype(this);
     1278    callHasProperty.append(branch32(Equal, Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::NullTag)));
     1279    loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
     1280    loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     1281    callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
     1282    addPtr(Imm32(sizeof(Structure*)), regT3);
     1283    branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
     1284
     1285    // Continue loop.
     1286    addJump(jump(), target);
     1287
     1288    // Slow case: Ask the object if i is valid.
     1289    callHasProperty.link(this);
     1290    loadPtr(addressFor(dst), regT1);
     1291    JITStubCall stubCall(this, cti_has_property);
    12071292    stubCall.addArgument(regT0);
     1293    stubCall.addArgument(regT1);
    12081294    stubCall.call();
    12091295
    1210     Jump endOfIter = branchTestPtr(Zero, regT0);
    1211     emitStore(dst, regT1, regT0);
    1212     map(m_bytecodeIndex + OPCODE_LENGTH(op_next_pname), dst, regT1, regT0);
    1213     addJump(jump(), target);
    1214     endOfIter.link(this);
     1296    // Test for valid key.
     1297    addJump(branchTest32(NonZero, regT0), target);
     1298    jump().linkTo(begin, this);
     1299
     1300    // End of loop.
     1301    end.link(this);
    12151302}
    12161303
     
    23732460}
    23742461
     2462void JIT::emit_op_get_pnames(Instruction* currentInstruction)
     2463{
     2464    int dst = currentInstruction[1].u.operand;
     2465    int base = currentInstruction[2].u.operand;
     2466    int i = currentInstruction[3].u.operand;
     2467    int size = currentInstruction[4].u.operand;
     2468    int breakTarget = currentInstruction[5].u.operand;
     2469
     2470    JumpList isNotObject;
     2471
     2472    emitGetVirtualRegister(base, regT0);
     2473    if (!m_codeBlock->isKnownNotImmediate(base))
     2474        isNotObject.append(emitJumpIfNotJSCell(regT0));
     2475    if (base != m_codeBlock->thisRegister()) {
     2476        loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     2477        isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
     2478    }
     2479
     2480    // We could inline the case where you have a valid cache, but
     2481    // this call doesn't seem to be hot.
     2482    Label isObject(this);
     2483    JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
     2484    getPnamesStubCall.addArgument(regT0);
     2485    getPnamesStubCall.call(dst);
     2486    load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
     2487    store32(Imm32(0), addressFor(i));
     2488    store32(regT3, addressFor(size));
     2489    Jump end = jump();
     2490
     2491    isNotObject.link(this);
     2492    move(regT0, regT1);
     2493    and32(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT1);
     2494    addJump(branch32(Equal, regT1, Imm32(JSImmediate::FullTagTypeNull)), breakTarget);
     2495
     2496    JITStubCall toObjectStubCall(this, cti_to_object);
     2497    toObjectStubCall.addArgument(regT0);
     2498    toObjectStubCall.call(base);
     2499    jump().linkTo(isObject, this);
     2500   
     2501    end.link(this);
     2502}
     2503
    23752504void JIT::emit_op_next_pname(Instruction* currentInstruction)
    23762505{
    2377     JITStubCall stubCall(this, cti_op_next_pname);
    2378     stubCall.addArgument(currentInstruction[2].u.operand, regT2);
     2506    int dst = currentInstruction[1].u.operand;
     2507    int base = currentInstruction[2].u.operand;
     2508    int i = currentInstruction[3].u.operand;
     2509    int size = currentInstruction[4].u.operand;
     2510    int it = currentInstruction[5].u.operand;
     2511    int target = currentInstruction[6].u.operand;
     2512   
     2513    JumpList callHasProperty;
     2514
     2515    Label begin(this);
     2516    load32(addressFor(i), regT0);
     2517    Jump end = branch32(Equal, regT0, addressFor(size));
     2518
     2519    // Grab key @ i
     2520    loadPtr(addressFor(it), regT1);
     2521    loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
     2522    loadPtr(BaseIndex(regT2, regT0, TimesEight), regT2);
     2523    emitPutVirtualRegister(dst, regT2);
     2524
     2525    // Increment i
     2526    add32(Imm32(1), regT0);
     2527    store32(regT0, addressFor(i));
     2528
     2529    // Verify that i is valid:
     2530    emitGetVirtualRegister(base, regT0);
     2531
     2532    // Test base's structure
     2533    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     2534    callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
     2535
     2536    // Test base's prototype chain
     2537    loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
     2538    loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
     2539    addJump(branchTestPtr(Zero, Address(regT3)), target);
     2540
     2541    Label checkPrototype(this);
     2542    loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2);
     2543    callHasProperty.append(emitJumpIfNotJSCell(regT2));
     2544    loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
     2545    callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
     2546    addPtr(Imm32(sizeof(Structure*)), regT3);
     2547    branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
     2548
     2549    // Continue loop.
     2550    addJump(jump(), target);
     2551
     2552    // Slow case: Ask the object if i is valid.
     2553    callHasProperty.link(this);
     2554    emitGetVirtualRegister(dst, regT1);
     2555    JITStubCall stubCall(this, cti_has_property);
     2556    stubCall.addArgument(regT0);
     2557    stubCall.addArgument(regT1);
    23792558    stubCall.call();
    2380     Jump endOfIter = branchTestPtr(Zero, regT0);
    2381     emitPutVirtualRegister(currentInstruction[1].u.operand);
    2382     addJump(jump(), currentInstruction[3].u.operand);
    2383     endOfIter.link(this);
     2559
     2560    // Test for valid key.
     2561    addJump(branchTest32(NonZero, regT0), target);
     2562    jump().linkTo(begin, this);
     2563
     2564    // End of loop.
     2565    end.link(this);
    23842566}
    23852567
  • trunk/JavaScriptCore/jit/JITStubs.cpp

    r49607 r49717  
    701701    // Structure transition, cache transition info
    702702    if (slot.type() == PutPropertySlot::NewProperty) {
    703         StructureChain* prototypeChain = structure->prototypeChain(callFrame);
    704         if (!prototypeChain->isCacheable() || structure->isDictionary()) {
     703        if (structure->isDictionary()) {
    705704            ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic));
    706705            return;
    707706        }
     707
     708        // put_by_id_transition checks the prototype chain for setters.
     709        normalizePrototypeChain(callFrame, baseCell);
     710
     711        StructureChain* prototypeChain = structure->prototypeChain(callFrame);
    708712        stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);
    709713        JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress);
     
    781785    }
    782786
    783     size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
     787    size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase());
    784788    if (!count) {
    785789        stubInfo->accessType = access_get_by_id_generic;
     
    788792
    789793    StructureChain* prototypeChain = structure->prototypeChain(callFrame);
    790     if (!prototypeChain->isCacheable()) {
    791         ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
    792         return;
    793     }
    794794    stubInfo->initGetByIdChain(structure, prototypeChain);
    795795    JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress);
     
    13331333        if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
    13341334            ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
    1335     } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) {
    1336         StructureChain* protoChain = structure->prototypeChain(callFrame);
    1337         if (!protoChain->isCacheable()) {
    1338             ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
    1339             return JSValue::encode(result);
    1340         }
    1341        
     1335    } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase())) {
    13421336        int listIndex;
    13431337        PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
     1338
     1339        StructureChain* protoChain = structure->prototypeChain(callFrame);
    13441340        JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset());
    13451341
     
    26722668    STUB_INIT_STACK_FRAME(stackFrame);
    26732669
    2674     return JSPropertyNameIterator::create(stackFrame.callFrame, stackFrame.args[0].jsValue());
    2675 }
    2676 
    2677 DEFINE_STUB_FUNCTION(EncodedJSValue, op_next_pname)
    2678 {
    2679     STUB_INIT_STACK_FRAME(stackFrame);
    2680 
    2681     JSPropertyNameIterator* it = stackFrame.args[0].propertyNameIterator();
    2682     JSValue temp = it->next(stackFrame.callFrame);
    2683     if (!temp)
    2684         it->invalidate();
    2685     return JSValue::encode(temp);
     2670    CallFrame* callFrame = stackFrame.callFrame;
     2671    JSObject* o = stackFrame.args[0].jsObject();
     2672    Structure* structure = o->structure();
     2673    JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
     2674    if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
     2675        jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
     2676    return jsPropertyNameIterator;
     2677}
     2678
     2679DEFINE_STUB_FUNCTION(int, has_property)
     2680{
     2681    STUB_INIT_STACK_FRAME(stackFrame);
     2682
     2683    JSObject* base = stackFrame.args[0].jsObject();
     2684    JSString* property = stackFrame.args[1].jsString();
     2685    return base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value()));
    26862686}
    26872687
     
    30243024}
    30253025
     3026DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
     3027{
     3028    STUB_INIT_STACK_FRAME(stackFrame);
     3029
     3030    CallFrame* callFrame = stackFrame.callFrame;
     3031    return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
     3032}
     3033
    30263034} // namespace JSC
    30273035
  • trunk/JavaScriptCore/jit/JITStubs.h

    r49065 r49717  
    6464
    6565        JSValue jsValue() { return JSValue::decode(asEncodedJSValue); }
     66        JSObject* jsObject() { return static_cast<JSObject*>(asPointer); }
    6667        Identifier& identifier() { return *static_cast<Identifier*>(asPointer); }
    6768        int32_t int32() { return asInt32; }
     
    286287    EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION);
    287288    EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION);
    288     EncodedJSValue JIT_STUB cti_op_next_pname(STUB_ARGS_DECLARATION);
    289289    EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION);
    290290    EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION);
     
    308308    EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION);
    309309    EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION);
     310    EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION);
    310311    JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION);
    311312    JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION);
     
    333334    int JIT_STUB cti_op_loop_if_true(STUB_ARGS_DECLARATION);
    334335    int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION);
     336    int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION);
    335337    void JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
    336338    void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
  • trunk/JavaScriptCore/parser/Nodes.cpp

    r48662 r49717  
    14691469        return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference.");
    14701470
    1471     RefPtr<Label> continueTarget = generator.newLabel();
    1472 
    14731471    generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
    14741472
    14751473    if (m_init)
    14761474        generator.emitNode(generator.ignoredResult(), m_init);
    1477     RegisterID* forInBase = generator.emitNode(m_expr);
    1478     RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
     1475
     1476    RefPtr<RegisterID> base = generator.newTemporary();
     1477    generator.emitNode(base.get(), m_expr);
     1478    RefPtr<RegisterID> i = generator.newTemporary();
     1479    RefPtr<RegisterID> size = generator.newTemporary();
     1480    RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget());
    14791481    generator.emitJump(scope->continueTarget());
    14801482
     
    15181520
    15191521    generator.emitLabel(scope->continueTarget());
    1520     generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get());
     1522    generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get());
    15211523    generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
    15221524    generator.emitLabel(scope->breakTarget());
  • trunk/JavaScriptCore/runtime/JSCell.h

    r49398 r49717  
    113113    };
    114114
    115     // FIXME: We should deprecate this and just use JSValue::asCell() instead.
    116     JSCell* asCell(JSValue);
    117 
    118     inline JSCell* asCell(JSValue value)
    119     {
    120         return value.asCell();
    121     }
    122 
    123115    inline JSCell::JSCell(Structure* structure)
    124116        : m_structure(structure)
  • trunk/JavaScriptCore/runtime/JSObject.cpp

    r49694 r49717  
    444444void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
    445445{
    446     bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_structure->isDictionary());
    447 
    448     if (shouldCache) {
    449         if (PropertyNameArrayData* data = m_structure->enumerationCache()) {
    450             if (data->cachedPrototypeChain() == m_structure->prototypeChain(exec)) {
    451                 propertyNames.setData(data);
    452                 return;
    453             }
    454 
    455             m_structure->clearEnumerationCache();
    456         }
    457     }
    458 
    459446    getOwnPropertyNames(exec, propertyNames);
    460447
    461     if (prototype().isObject()) {
    462         propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly.
    463         JSObject* prototype = asObject(this->prototype());
    464         while(1) {
    465             if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
    466                 prototype->getPropertyNames(exec, propertyNames);
    467                 break;
    468             }
    469             prototype->getOwnPropertyNames(exec, propertyNames);
    470             JSValue nextProto = prototype->prototype();
    471             if (!nextProto.isObject())
    472                 break;
    473             prototype = asObject(nextProto);
    474         }
    475     }
    476 
    477     if (shouldCache) {
    478         StructureChain* protoChain = m_structure->prototypeChain(exec);
    479         if (!protoChain->isCacheable())
    480             return;
    481         RefPtr<PropertyNameArrayData> data = propertyNames.data();
    482         data->setCachedPrototypeChain(protoChain);
    483         data->setCachedStructure(m_structure);
    484         m_structure->setEnumerationCache(data.release());
     448    if (prototype().isNull())
     449        return;
     450
     451    JSObject* prototype = asObject(this->prototype());
     452    while(1) {
     453        if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
     454            prototype->getPropertyNames(exec, propertyNames);
     455            break;
     456        }
     457        prototype->getOwnPropertyNames(exec, propertyNames);
     458        JSValue nextProto = prototype->prototype();
     459        if (nextProto.isNull())
     460            break;
     461        prototype = asObject(nextProto);
    485462    }
    486463}
  • trunk/JavaScriptCore/runtime/JSPropertyNameIterator.cpp

    r47799 r49717  
    3030#include "JSPropertyNameIterator.h"
    3131
     32#include "JSGlobalObject.h"
     33
    3234namespace JSC {
    3335
    3436ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator);
    3537
    36 JSPropertyNameIterator::~JSPropertyNameIterator()
     38JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
    3739{
     40    ASSERT(!o->structure()->enumerationCache() ||
     41            o->structure()->enumerationCache()->cachedStructure() != o->structure() ||
     42            o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec));
     43
     44    PropertyNameArray propertyNames(exec);
     45    o->getPropertyNames(exec, propertyNames);
     46    JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data());
     47
     48    if (o->structure()->isDictionary())
     49        return jsPropertyNameIterator;
     50
     51    if (o->structure()->typeInfo().overridesGetPropertyNames())
     52        return jsPropertyNameIterator;
     53   
     54    size_t count = normalizePrototypeChain(exec, o);
     55    StructureChain* structureChain = o->structure()->prototypeChain(exec);
     56    RefPtr<Structure>* structure = structureChain->head();
     57    for (size_t i = 0; i < count; ++i) {
     58        if (structure[i]->typeInfo().overridesGetPropertyNames())
     59            return jsPropertyNameIterator;
     60    }
     61
     62    jsPropertyNameIterator->setCachedPrototypeChain(structureChain);
     63    jsPropertyNameIterator->setCachedStructure(o->structure());
     64    o->structure()->setEnumerationCache(jsPropertyNameIterator);
     65    return jsPropertyNameIterator;
     66}
     67
     68JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
     69{
     70    JSValue& identifier = m_jsStrings[i];
     71    if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec))
     72        return identifier;
     73
     74    if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value())))
     75        return JSValue();
     76    return identifier;
    3877}
    3978
    4079void JSPropertyNameIterator::markChildren(MarkStack& markStack)
    4180{
    42     JSCell::markChildren(markStack);
    43     if (m_object)
    44         markStack.append(m_object);
    45 }
    46 
    47 void JSPropertyNameIterator::invalidate()
    48 {
    49     ASSERT(m_position == m_end);
    50     m_object = 0;
    51     m_data.clear();
     81    markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues);
    5282}
    5383
  • trunk/JavaScriptCore/runtime/JSPropertyNameIterator.h

    r49649 r49717  
    3232#include "JSObject.h"
    3333#include "JSString.h"
     34#include "Operations.h"
    3435#include "PropertyNameArray.h"
    3536
     
    4041
    4142    class JSPropertyNameIterator : public JSCell {
     43        friend class JIT;
     44
    4245    public:
    43         static JSPropertyNameIterator* create(ExecState*, JSValue);
    44 
    45         virtual ~JSPropertyNameIterator();
    46 
    47         virtual void markChildren(MarkStack&);
    48 
    49         JSValue next(ExecState*);
    50         void invalidate();
     46        static JSPropertyNameIterator* create(ExecState*, JSObject*);
    5147       
    5248        static PassRefPtr<Structure> createStructure(JSValue prototype)
     
    5450            return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren));
    5551        }
     52
     53        virtual void markChildren(MarkStack&);
     54
     55        JSValue get(ExecState*, JSObject*, size_t i);
     56        size_t size() { return m_jsStringsSize; }
     57
     58        void setCachedStructure(Structure* structure) { m_cachedStructure = structure; }
     59        Structure* cachedStructure() { return m_cachedStructure; }
     60
     61        void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
     62        StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
     63
    5664    private:
    57         JSPropertyNameIterator(ExecState*);
    58         JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData);
     65        JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData);
    5966
    60         JSObject* m_object;
    61         RefPtr<PropertyNameArrayData> m_data;
    62         PropertyNameArrayData::const_iterator m_position;
    63         PropertyNameArrayData::const_iterator m_end;
     67        Structure* m_cachedStructure;
     68        RefPtr<StructureChain> m_cachedPrototypeChain;
     69        size_t m_jsStringsSize;
     70        OwnArrayPtr<JSValue> m_jsStrings;
    6471    };
    6572
    66 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec)
     73inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
    6774    : JSCell(exec->globalData().propertyNameIteratorStructure.get())
    68     , m_object(0)
    69     , m_position(0)
    70     , m_end(0)
     75    , m_cachedStructure(0)
     76    , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
     77    , m_jsStrings(new JSValue[m_jsStringsSize])
    7178{
     79    PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
     80    for (size_t i = 0; i < m_jsStringsSize; ++i)
     81        m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring());
    7282}
    7383
    74 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData)
    75     : JSCell(exec->globalData().propertyNameIteratorStructure.get())
    76     , m_object(object)
    77     , m_data(propertyNameArrayData)
    78     , m_position(m_data->begin())
    79     , m_end(m_data->end())
     84inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache)
    8085{
    81 }
    82 
    83 inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v)
    84 {
    85     if (v.isUndefinedOrNull())
    86         return new (exec) JSPropertyNameIterator(exec);
    87 
    88     JSObject* o = v.toObject(exec);
    89     PropertyNameArray propertyNames(exec);
    90     o->getPropertyNames(exec, propertyNames);
    91     return new (exec) JSPropertyNameIterator(exec, o, propertyNames.releaseData());
    92 }
    93 
    94 inline JSValue JSPropertyNameIterator::next(ExecState* exec)
    95 {
    96     if (m_position == m_end)
    97         return JSValue();
    98 
    99     if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec))
    100         return jsOwnedString(exec, (*m_position++).ustring());
    101 
    102     do {
    103         if (m_object->hasProperty(exec, *m_position))
    104             return jsOwnedString(exec, (*m_position++).ustring());
    105         m_position++;
    106     } while (m_position != m_end);
    107 
    108     return JSValue();
     86    ASSERT(!isDictionary());
     87    m_enumerationCache = enumerationCache;
    10988}
    11089
  • trunk/JavaScriptCore/runtime/JSValue.h

    r49030 r49717  
    374374    }
    375375
     376    // FIXME: We should deprecate this and just use JSValue::asCell() instead.
     377    JSCell* asCell(JSValue);
     378
     379    inline JSCell* asCell(JSValue value)
     380    {
     381        return value.asCell();
     382    }
     383
    376384    ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
    377385    {
  • trunk/JavaScriptCore/runtime/MarkStack.h

    r48788 r49717  
    4848
    4949        ALWAYS_INLINE void append(JSValue);
    50         ALWAYS_INLINE void append(JSCell*);
     50        void append(JSCell*);
    5151       
    5252        ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues)
  • trunk/JavaScriptCore/runtime/ObjectConstructor.cpp

    r48836 r49717  
    126126}
    127127
     128// FIXME: Use the enumeration cache.
    128129JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
    129130{
  • trunk/JavaScriptCore/runtime/Operations.h

    r47622 r49717  
    225225    }
    226226
    227     inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot)
    228     {
    229         JSCell* cell = asCell(baseValue);
     227    inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase)
     228    {
     229        JSCell* cell = asCell(base);
    230230        size_t count = 0;
    231231
    232         while (slot.slotBase() != cell) {
     232        while (slotBase != cell) {
    233233            JSValue v = cell->structure()->prototypeForLookup(callFrame);
    234234
    235             // If we didn't find slotBase in baseValue's prototype chain, then baseValue
     235            // If we didn't find slotBase in base's prototype chain, then base
    236236            // must be a proxy for another object.
    237237
     
    251251        ASSERT(count);
    252252        return count;
     253    }
     254
     255    inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
     256    {
     257        size_t count = 0;
     258        while (1) {
     259            JSValue v = base->structure()->prototypeForLookup(callFrame);
     260            if (v.isNull())
     261                return count;
     262
     263            base = asCell(v);
     264
     265            // Since we're accessing a prototype in a loop, it's a good bet that it
     266            // should not be treated as a dictionary.
     267            if (base->structure()->isDictionary())
     268                asObject(base)->setStructure(Structure::fromDictionaryTransition(base->structure()));
     269
     270            ++count;
     271        }
    253272    }
    254273
  • trunk/JavaScriptCore/runtime/PropertyNameArray.cpp

    r49398 r49717  
    4848    }
    4949
    50     m_data->propertyNameVector().append(Identifier(m_globalData, identifier));
     50    addKnownUnique(identifier);
    5151}
    5252
  • trunk/JavaScriptCore/runtime/PropertyNameArray.h

    r49398 r49717  
    2525#include "Identifier.h"
    2626#include <wtf/HashSet.h>
     27#include <wtf/OwnArrayPtr.h>
    2728#include <wtf/Vector.h>
    2829
     
    3233    class StructureChain;
    3334
     35    // FIXME: Rename to PropertyNameArray.
    3436    class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
    3537    public:
    3638        typedef Vector<Identifier, 20> PropertyNameVector;
    37         typedef PropertyNameVector::const_iterator const_iterator;
    3839
    3940        static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
    4041
    41         const_iterator begin() const { return m_propertyNameVector.begin(); }
    42         const_iterator end() const { return m_propertyNameVector.end(); }
    43 
    4442        PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
    45 
    46         void setCachedStructure(Structure* structure) { m_cachedStructure = structure; }
    47         Structure* cachedStructure() const { return m_cachedStructure; }
    48 
    49         void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
    50         StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
    5143
    5244    private:
    5345        PropertyNameArrayData()
    54             : m_cachedStructure(0)
    5546        {
    5647        }
    5748
    5849        PropertyNameVector m_propertyNameVector;
    59         Structure* m_cachedStructure;
    60         RefPtr<StructureChain> m_cachedPrototypeChain;
    6150    };
    6251
     52    // FIXME: Rename to PropertyNameArrayBuilder.
    6353    class PropertyNameArray {
    6454    public:
    65         typedef PropertyNameArrayData::const_iterator const_iterator;
    66 
    6755        PropertyNameArray(JSGlobalData* globalData)
    6856            : m_data(PropertyNameArrayData::create())
     
    8573        void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); }
    8674
    87         size_t size() const { return m_data->propertyNameVector().size(); }
    88 
    8975        Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
    9076        const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
    9177
    92         const_iterator begin() const { return m_data->begin(); }
    93         const_iterator end() const { return m_data->end(); }
    94 
    9578        void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
    9679        PropertyNameArrayData* data() { return m_data.get(); }
    97 
    9880        PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
    9981
    100         void setShouldCache(bool shouldCache) { m_shouldCache = shouldCache; }
    101         bool shouldCache() const { return m_shouldCache; }
     82        // FIXME: Remove these functions.
     83        typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
     84        size_t size() const { return m_data->propertyNameVector().size(); }
     85        const_iterator begin() const { return m_data->propertyNameVector().begin(); }
     86        const_iterator end() const { return m_data->propertyNameVector().end(); }
    10287
    10388    private:
  • trunk/JavaScriptCore/runtime/Protect.h

    r44224 r49717  
    2323#define Protect_h
    2424
    25 #include "JSCell.h"
    2625#include "Collector.h"
     26#include "JSValue.h"
    2727
    2828namespace JSC {
  • trunk/JavaScriptCore/runtime/Structure.cpp

    r49398 r49717  
    2929#include "Identifier.h"
    3030#include "JSObject.h"
     31#include "JSPropertyNameIterator.h"
     32#include "Lookup.h"
    3133#include "PropertyNameArray.h"
    3234#include "StructureChain.h"
    33 #include "Lookup.h"
    3435#include <wtf/RefCountedLeakCounter.h>
    3536#include <wtf/RefPtr.h>
     
    160161
    161162    }
    162 
    163     if (m_cachedPropertyNameArrayData)
    164         m_cachedPropertyNameArrayData->setCachedStructure(0);
     163   
     164    if (m_enumerationCache)
     165        m_enumerationCache->setCachedStructure(0);
    165166
    166167    if (m_propertyTable) {
     
    281282        insertIntoPropertyMapHashTable(entry);
    282283    }
    283 }
    284 
    285 void Structure::clearEnumerationCache()
    286 {
    287     if (m_cachedPropertyNameArrayData)
    288         m_cachedPropertyNameArrayData->setCachedStructure(0);
    289     m_cachedPropertyNameArrayData.clear();
    290284}
    291285
     
    553547size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
    554548{
     549    ASSERT(!m_enumerationCache);
    555550    materializePropertyMapIfNecessary();
    556551
     
    559554    if (propertyStorageSize() > propertyStorageCapacity())
    560555        growPropertyStorageCapacity();
    561     clearEnumerationCache();
    562556    return offset;
    563557}
     
    566560{
    567561    ASSERT(isUncacheableDictionary());
     562    ASSERT(!m_enumerationCache);
    568563
    569564    materializePropertyMapIfNecessary();
     
    571566    m_isPinnedPropertyTable = true;
    572567    size_t offset = remove(propertyName);
    573     clearEnumerationCache();
    574568    return offset;
    575569}
  • trunk/JavaScriptCore/runtime/Structure.h

    r49398 r49717  
    3232#include "PropertyMapHashTable.h"
    3333#include "PropertyNameArray.h"
     34#include "Protect.h"
    3435#include "StructureChain.h"
    3536#include "StructureTransitionTable.h"
     
    124125        void despecifyDictionaryFunction(const Identifier& propertyName);
    125126
    126         void setEnumerationCache(PassRefPtr<PropertyNameArrayData> data) { m_cachedPropertyNameArrayData = data; }
    127         PropertyNameArrayData* enumerationCache() { return m_cachedPropertyNameArrayData.get(); }
    128         void clearEnumerationCache();
     127        void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
     128        JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); }
    129129        void getEnumerablePropertyNames(PropertyNameArray&);
    130130
     
    187187        StructureTransitionTable table;
    188188
    189         RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
     189        ProtectedPtr<JSPropertyNameIterator> m_enumerationCache;
    190190
    191191        PropertyMapHashTable* m_propertyTable;
  • trunk/JavaScriptCore/runtime/StructureChain.cpp

    r49694 r49717  
    4747}
    4848
    49 bool StructureChain::isCacheable() const
    50 {
    51     uint32_t i = 0;
    52    
    53     while (m_vector[i]) {
    54         // Both classes of dictionary structure may change arbitrarily so we can't cache them
    55         if (m_vector[i]->isDictionary())
    56             return false;
    57         if (m_vector[i++]->typeInfo().overridesGetPropertyNames())
    58             return false;
    59     }
    60     return true;
    61 }
    62 
    6349} // namespace JSC
  • trunk/JavaScriptCore/runtime/StructureChain.h

    r45039 r49717  
    3737
    3838    class StructureChain : public RefCounted<StructureChain> {
     39        friend class JIT;
     40
    3941    public:
    4042        static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); }
    4143        RefPtr<Structure>* head() { return m_vector.get(); }
    42         bool isCacheable() const;
    4344
    4445    private:
Note: See TracChangeset for help on using the changeset viewer.