Changeset 49717 in webkit
- Timestamp:
- Oct 16, 2009, 5:28:19 PM (16 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r49705 r49717 1 2009-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 1 117 2009-10-16 Steve Falkenburg <[email protected]> 2 118 -
trunk/JavaScriptCore/bytecode/CodeBlock.cpp
r49409 r49717 1016 1016 } 1017 1017 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; 1020 1020 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; 1021 1022 break; 1022 1023 } 1023 1024 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; 1027 1028 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; 1028 1030 break; 1029 1031 } -
trunk/JavaScriptCore/bytecode/Opcode.h
r46598 r49717 153 153 macro(op_to_primitive, 3) \ 154 154 \ 155 macro(op_get_pnames, 3) \156 macro(op_next_pname, 4) \155 macro(op_get_pnames, 6) \ 156 macro(op_next_pname, 7) \ 157 157 \ 158 158 macro(op_push_scope, 2) \ -
trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r49409 r49717 1795 1795 } 1796 1796 1797 RegisterID* BytecodeGenerator::emit NextPropertyName(RegisterID* dst, RegisterID* iter, Label* target)1797 RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) 1798 1798 { 1799 1799 size_t begin = instructions().size(); 1800 1800 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 1810 RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target) 1811 { 1812 size_t begin = instructions().size(); 1813 1801 1814 emitOpcode(op_next_pname); 1802 1815 instructions().append(dst->index()); 1816 instructions().append(base->index()); 1817 instructions().append(i->index()); 1818 instructions().append(size->index()); 1803 1819 instructions().append(iter->index()); 1804 1820 instructions().append(target->bind(begin, instructions().size())); -
trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r48662 r49717 313 313 void emitSubroutineReturn(RegisterID* retAddrSrc); 314 314 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); 317 317 318 318 RegisterID* emitCatch(RegisterID*, Label* start, Label* end); -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r49409 r49717 939 939 } 940 940 941 StructureChain* protoChain = structure->prototypeChain(callFrame);942 if (!protoChain->isCacheable()) {943 vPC[0] = getOpcode(op_put_by_id_generic);944 return;945 }946 947 941 // Structure transition, cache transition info 948 942 if (slot.type() == PutPropertySlot::NewProperty) { … … 951 945 return; 952 946 } 947 948 // put_by_id_transition checks the prototype chain for setters. 949 normalizePrototypeChain(callFrame, baseCell); 950 953 951 vPC[0] = getOpcode(op_put_by_id_transition); 954 952 vPC[4] = structure->previousID(); 955 953 vPC[5] = structure; 956 vPC[6] = protoChain;954 vPC[6] = structure->prototypeChain(callFrame); 957 955 vPC[7] = slot.cachedOffset(); 958 956 codeBlock->refStructures(vPC); … … 1050 1048 } 1051 1049 1052 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);1050 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase()); 1053 1051 if (!count) { 1054 1052 vPC[0] = getOpcode(op_get_by_id_generic); … … 1056 1054 } 1057 1055 1058 StructureChain* protoChain = structure->prototypeChain(callFrame);1059 if (!protoChain->isCacheable()) {1060 vPC[0] = getOpcode(op_get_by_id_generic);1061 return;1062 }1063 1064 1056 vPC[0] = getOpcode(op_get_by_id_chain); 1065 1057 vPC[4] = structure; 1066 vPC[5] = protoChain;1058 vPC[5] = structure->prototypeChain(callFrame); 1067 1059 vPC[6] = count; 1068 1060 vPC[7] = slot.cachedOffset(); … … 3503 3495 } 3504 3496 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) 3506 3498 3507 3499 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. 3511 3502 */ 3512 3503 int dst = vPC[1].u.operand; 3513 3504 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()); 3516 3525 vPC += OPCODE_LENGTH(op_get_pnames); 3517 3526 NEXT_INSTRUCTION(); 3518 3527 } 3519 3528 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 3526 3534 instruction. 3527 3535 */ 3528 3536 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; 3531 3542 3532 3543 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 } 3540 3554 3541 3555 vPC += OPCODE_LENGTH(op_next_pname); -
trunk/JavaScriptCore/jit/JIT.cpp
r49409 r49717 203 203 DEFINE_BINARY_OP(op_lesseq) 204 204 DEFINE_BINARY_OP(op_urshift) 205 DEFINE_UNARY_OP(op_get_pnames)206 205 DEFINE_UNARY_OP(op_is_boolean) 207 206 DEFINE_UNARY_OP(op_is_function) … … 242 241 DEFINE_OP(op_get_by_val) 243 242 DEFINE_OP(op_get_global_var) 243 DEFINE_OP(op_get_pnames) 244 244 DEFINE_OP(op_get_scoped_var) 245 245 DEFINE_OP(op_instanceof) -
trunk/JavaScriptCore/jit/JIT.h
r48920 r49717 714 714 void emit_op_new_object(Instruction*); 715 715 void emit_op_new_regexp(Instruction*); 716 void emit_op_get_pnames(Instruction*); 716 717 void emit_op_next_pname(Instruction*); 717 718 void emit_op_not(Instruction*); -
trunk/JavaScriptCore/jit/JITOpcodes.cpp
r49509 r49717 34 34 #include "JSCell.h" 35 35 #include "JSFunction.h" 36 #include "JSPropertyNameIterator.h" 36 37 #include "LinkBuffer.h" 37 38 … … 1196 1197 } 1197 1198 1199 void 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 1198 1239 void JIT::emit_op_next_pname(Instruction* currentInstruction) 1199 1240 { 1200 1241 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); 1207 1292 stubCall.addArgument(regT0); 1293 stubCall.addArgument(regT1); 1208 1294 stubCall.call(); 1209 1295 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); 1215 1302 } 1216 1303 … … 2373 2460 } 2374 2461 2462 void 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 2375 2504 void JIT::emit_op_next_pname(Instruction* currentInstruction) 2376 2505 { 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); 2379 2558 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); 2384 2566 } 2385 2567 -
trunk/JavaScriptCore/jit/JITStubs.cpp
r49607 r49717 701 701 // Structure transition, cache transition info 702 702 if (slot.type() == PutPropertySlot::NewProperty) { 703 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 704 if (!prototypeChain->isCacheable() || structure->isDictionary()) { 703 if (structure->isDictionary()) { 705 704 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); 706 705 return; 707 706 } 707 708 // put_by_id_transition checks the prototype chain for setters. 709 normalizePrototypeChain(callFrame, baseCell); 710 711 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 708 712 stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); 709 713 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); … … 781 785 } 782 786 783 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);787 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase()); 784 788 if (!count) { 785 789 stubInfo->accessType = access_get_by_id_generic; … … 788 792 789 793 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 790 if (!prototypeChain->isCacheable()) {791 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));792 return;793 }794 794 stubInfo->initGetByIdChain(structure, prototypeChain); 795 795 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress); … … 1333 1333 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1334 1334 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())) { 1342 1336 int listIndex; 1343 1337 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); 1338 1339 StructureChain* protoChain = structure->prototypeChain(callFrame); 1344 1340 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset()); 1345 1341 … … 2672 2668 STUB_INIT_STACK_FRAME(stackFrame); 2673 2669 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 2679 DEFINE_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())); 2686 2686 } 2687 2687 … … 3024 3024 } 3025 3025 3026 DEFINE_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 3026 3034 } // namespace JSC 3027 3035 -
trunk/JavaScriptCore/jit/JITStubs.h
r49065 r49717 64 64 65 65 JSValue jsValue() { return JSValue::decode(asEncodedJSValue); } 66 JSObject* jsObject() { return static_cast<JSObject*>(asPointer); } 66 67 Identifier& identifier() { return *static_cast<Identifier*>(asPointer); } 67 68 int32_t int32() { return asInt32; } … … 286 287 EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION); 287 288 EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION); 288 EncodedJSValue JIT_STUB cti_op_next_pname(STUB_ARGS_DECLARATION);289 289 EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION); 290 290 EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION); … … 308 308 EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION); 309 309 EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION); 310 EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION); 310 311 JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION); 311 312 JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION); … … 333 334 int JIT_STUB cti_op_loop_if_true(STUB_ARGS_DECLARATION); 334 335 int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION); 336 int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION); 335 337 void JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION); 336 338 void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION); -
trunk/JavaScriptCore/parser/Nodes.cpp
r48662 r49717 1469 1469 return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); 1470 1470 1471 RefPtr<Label> continueTarget = generator.newLabel();1472 1473 1471 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); 1474 1472 1475 1473 if (m_init) 1476 1474 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()); 1479 1481 generator.emitJump(scope->continueTarget()); 1480 1482 … … 1518 1520 1519 1521 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()); 1521 1523 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); 1522 1524 generator.emitLabel(scope->breakTarget()); -
trunk/JavaScriptCore/runtime/JSCell.h
r49398 r49717 113 113 }; 114 114 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 123 115 inline JSCell::JSCell(Structure* structure) 124 116 : m_structure(structure) -
trunk/JavaScriptCore/runtime/JSObject.cpp
r49694 r49717 444 444 void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) 445 445 { 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 459 446 getOwnPropertyNames(exec, propertyNames); 460 447 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); 485 462 } 486 463 } -
trunk/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
r47799 r49717 30 30 #include "JSPropertyNameIterator.h" 31 31 32 #include "JSGlobalObject.h" 33 32 34 namespace JSC { 33 35 34 36 ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); 35 37 36 JSPropertyNameIterator ::~JSPropertyNameIterator()38 JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) 37 39 { 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 68 JSValue 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; 38 77 } 39 78 40 79 void JSPropertyNameIterator::markChildren(MarkStack& markStack) 41 80 { 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); 52 82 } 53 83 -
trunk/JavaScriptCore/runtime/JSPropertyNameIterator.h
r49649 r49717 32 32 #include "JSObject.h" 33 33 #include "JSString.h" 34 #include "Operations.h" 34 35 #include "PropertyNameArray.h" 35 36 … … 40 41 41 42 class JSPropertyNameIterator : public JSCell { 43 friend class JIT; 44 42 45 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*); 51 47 52 48 static PassRefPtr<Structure> createStructure(JSValue prototype) … … 54 50 return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren)); 55 51 } 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 56 64 private: 57 JSPropertyNameIterator(ExecState*); 58 JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData); 65 JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData); 59 66 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; 64 71 }; 65 72 66 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec )73 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData) 67 74 : 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]) 71 78 { 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()); 72 82 } 73 83 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()) 84 inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) 80 85 { 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; 109 88 } 110 89 -
trunk/JavaScriptCore/runtime/JSValue.h
r49030 r49717 374 374 } 375 375 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 376 384 ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const 377 385 { -
trunk/JavaScriptCore/runtime/MarkStack.h
r48788 r49717 48 48 49 49 ALWAYS_INLINE void append(JSValue); 50 ALWAYS_INLINEvoid append(JSCell*);50 void append(JSCell*); 51 51 52 52 ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues) -
trunk/JavaScriptCore/runtime/ObjectConstructor.cpp
r48836 r49717 126 126 } 127 127 128 // FIXME: Use the enumeration cache. 128 129 JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args) 129 130 { -
trunk/JavaScriptCore/runtime/Operations.h
r47622 r49717 225 225 } 226 226 227 inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot)228 { 229 JSCell* cell = asCell(base Value);227 inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase) 228 { 229 JSCell* cell = asCell(base); 230 230 size_t count = 0; 231 231 232 while (slot .slotBase()!= cell) {232 while (slotBase != cell) { 233 233 JSValue v = cell->structure()->prototypeForLookup(callFrame); 234 234 235 // If we didn't find slotBase in base Value's prototype chain, then baseValue235 // If we didn't find slotBase in base's prototype chain, then base 236 236 // must be a proxy for another object. 237 237 … … 251 251 ASSERT(count); 252 252 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 } 253 272 } 254 273 -
trunk/JavaScriptCore/runtime/PropertyNameArray.cpp
r49398 r49717 48 48 } 49 49 50 m_data->propertyNameVector().append(Identifier(m_globalData, identifier));50 addKnownUnique(identifier); 51 51 } 52 52 -
trunk/JavaScriptCore/runtime/PropertyNameArray.h
r49398 r49717 25 25 #include "Identifier.h" 26 26 #include <wtf/HashSet.h> 27 #include <wtf/OwnArrayPtr.h> 27 28 #include <wtf/Vector.h> 28 29 … … 32 33 class StructureChain; 33 34 35 // FIXME: Rename to PropertyNameArray. 34 36 class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { 35 37 public: 36 38 typedef Vector<Identifier, 20> PropertyNameVector; 37 typedef PropertyNameVector::const_iterator const_iterator;38 39 39 40 static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); } 40 41 41 const_iterator begin() const { return m_propertyNameVector.begin(); }42 const_iterator end() const { return m_propertyNameVector.end(); }43 44 42 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(); }51 43 52 44 private: 53 45 PropertyNameArrayData() 54 : m_cachedStructure(0)55 46 { 56 47 } 57 48 58 49 PropertyNameVector m_propertyNameVector; 59 Structure* m_cachedStructure;60 RefPtr<StructureChain> m_cachedPrototypeChain;61 50 }; 62 51 52 // FIXME: Rename to PropertyNameArrayBuilder. 63 53 class PropertyNameArray { 64 54 public: 65 typedef PropertyNameArrayData::const_iterator const_iterator;66 67 55 PropertyNameArray(JSGlobalData* globalData) 68 56 : m_data(PropertyNameArrayData::create()) … … 85 73 void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } 86 74 87 size_t size() const { return m_data->propertyNameVector().size(); }88 89 75 Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } 90 76 const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } 91 77 92 const_iterator begin() const { return m_data->begin(); }93 const_iterator end() const { return m_data->end(); }94 95 78 void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } 96 79 PropertyNameArrayData* data() { return m_data.get(); } 97 98 80 PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } 99 81 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(); } 102 87 103 88 private: -
trunk/JavaScriptCore/runtime/Protect.h
r44224 r49717 23 23 #define Protect_h 24 24 25 #include "JSCell.h"26 25 #include "Collector.h" 26 #include "JSValue.h" 27 27 28 28 namespace JSC { -
trunk/JavaScriptCore/runtime/Structure.cpp
r49398 r49717 29 29 #include "Identifier.h" 30 30 #include "JSObject.h" 31 #include "JSPropertyNameIterator.h" 32 #include "Lookup.h" 31 33 #include "PropertyNameArray.h" 32 34 #include "StructureChain.h" 33 #include "Lookup.h"34 35 #include <wtf/RefCountedLeakCounter.h> 35 36 #include <wtf/RefPtr.h> … … 160 161 161 162 } 162 163 if (m_ cachedPropertyNameArrayData)164 m_ cachedPropertyNameArrayData->setCachedStructure(0);163 164 if (m_enumerationCache) 165 m_enumerationCache->setCachedStructure(0); 165 166 166 167 if (m_propertyTable) { … … 281 282 insertIntoPropertyMapHashTable(entry); 282 283 } 283 }284 285 void Structure::clearEnumerationCache()286 {287 if (m_cachedPropertyNameArrayData)288 m_cachedPropertyNameArrayData->setCachedStructure(0);289 m_cachedPropertyNameArrayData.clear();290 284 } 291 285 … … 553 547 size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) 554 548 { 549 ASSERT(!m_enumerationCache); 555 550 materializePropertyMapIfNecessary(); 556 551 … … 559 554 if (propertyStorageSize() > propertyStorageCapacity()) 560 555 growPropertyStorageCapacity(); 561 clearEnumerationCache();562 556 return offset; 563 557 } … … 566 560 { 567 561 ASSERT(isUncacheableDictionary()); 562 ASSERT(!m_enumerationCache); 568 563 569 564 materializePropertyMapIfNecessary(); … … 571 566 m_isPinnedPropertyTable = true; 572 567 size_t offset = remove(propertyName); 573 clearEnumerationCache();574 568 return offset; 575 569 } -
trunk/JavaScriptCore/runtime/Structure.h
r49398 r49717 32 32 #include "PropertyMapHashTable.h" 33 33 #include "PropertyNameArray.h" 34 #include "Protect.h" 34 35 #include "StructureChain.h" 35 36 #include "StructureTransitionTable.h" … … 124 125 void despecifyDictionaryFunction(const Identifier& propertyName); 125 126 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(); } 129 129 void getEnumerablePropertyNames(PropertyNameArray&); 130 130 … … 187 187 StructureTransitionTable table; 188 188 189 RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;189 ProtectedPtr<JSPropertyNameIterator> m_enumerationCache; 190 190 191 191 PropertyMapHashTable* m_propertyTable; -
trunk/JavaScriptCore/runtime/StructureChain.cpp
r49694 r49717 47 47 } 48 48 49 bool StructureChain::isCacheable() const50 {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 them55 if (m_vector[i]->isDictionary())56 return false;57 if (m_vector[i++]->typeInfo().overridesGetPropertyNames())58 return false;59 }60 return true;61 }62 63 49 } // namespace JSC -
trunk/JavaScriptCore/runtime/StructureChain.h
r45039 r49717 37 37 38 38 class StructureChain : public RefCounted<StructureChain> { 39 friend class JIT; 40 39 41 public: 40 42 static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); } 41 43 RefPtr<Structure>* head() { return m_vector.get(); } 42 bool isCacheable() const;43 44 44 45 private:
Note:
See TracChangeset
for help on using the changeset viewer.