Changeset 48580 in webkit for trunk/JavaScriptCore
- Timestamp:
- Sep 21, 2009, 7:45:23 AM (16 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r48578 r48580 18 18 (JSC::JITThunks::JITThunks): 19 19 * jit/JITStubs.h: 20 21 2009-09-20 Oliver Hunt <[email protected]>22 23 Reviewed by Maciej Stachowiak.24 25 SNES is too slow26 https://bugs.webkit.org/show_bug.cgi?id=2953427 28 The problem was that the emulator used multiple classes with29 more properties than our dictionary cutoff allowed, this resulted30 in more or less all critical logic inside the emulator requiring31 uncached property access.32 33 Rather than simply bumping the dictionary cutoff, this patch34 recognises that there are two ways to create a "dictionary"35 structure. Either by adding a large number of properties, or36 by removing a property. In the case of adding properties we37 know all the existing properties will maintain their existing38 offsets, so we could cache access to those properties, if we39 know they won't be removed.40 41 To make this possible, this patch adds the logic required to42 distinguish a dictionary created by addition from one created43 by removal. With this logic in place we can now cache access44 to objects with large numbers of properties.45 46 SNES performance improved by more than 6x.47 48 * interpreter/Interpreter.cpp:49 (JSC::Interpreter::resolveGlobal):50 (JSC::Interpreter::tryCachePutByID):51 (JSC::Interpreter::tryCacheGetByID):52 * jit/JITStubs.cpp:53 (JSC::JITThunks::tryCachePutByID):54 (JSC::JITThunks::tryCacheGetByID):55 (JSC::DEFINE_STUB_FUNCTION):56 * runtime/BatchedTransitionOptimizer.h:57 (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer):58 * runtime/JSObject.cpp:59 (JSC::JSObject::removeDirect):60 * runtime/Structure.cpp:61 (JSC::Structure::Structure):62 (JSC::Structure::getEnumerablePropertyNames):63 (JSC::Structure::despecifyDictionaryFunction):64 (JSC::Structure::addPropertyTransitionToExistingStructure):65 (JSC::Structure::addPropertyTransition):66 (JSC::Structure::removePropertyTransition):67 (JSC::Structure::toDictionaryTransition):68 (JSC::Structure::toCacheableDictionaryTransition):69 (JSC::Structure::toUncacheableDictionaryTransition):70 (JSC::Structure::fromDictionaryTransition):71 (JSC::Structure::removePropertyWithoutTransition):72 * runtime/Structure.h:73 (JSC::Structure::isDictionary):74 (JSC::Structure::isUncacheableDictionary):75 (JSC::Structure::):76 * runtime/StructureChain.cpp:77 (JSC::StructureChain::isCacheable):78 20 79 21 2009-09-19 Oliver Hunt <[email protected]> -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r48573 r48580 170 170 if (globalObject->getPropertySlot(callFrame, ident, slot)) { 171 171 JSValue result = slot.getValue(callFrame, ident); 172 if (slot.isCacheable() && !globalObject->structure()->is UncacheableDictionary() && slot.slotBase() == globalObject) {172 if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) { 173 173 if (vPC[4].u.structure) 174 174 vPC[4].u.structure->deref(); … … 954 954 Structure* structure = baseCell->structure(); 955 955 956 if (structure->is UncacheableDictionary()) {956 if (structure->isDictionary()) { 957 957 vPC[0] = getOpcode(op_put_by_id_generic); 958 958 return; … … 1041 1041 Structure* structure = asCell(baseValue)->structure(); 1042 1042 1043 if (structure->is UncacheableDictionary()) {1043 if (structure->isDictionary()) { 1044 1044 vPC[0] = getOpcode(op_get_by_id_generic); 1045 1045 return; -
trunk/JavaScriptCore/jit/JITStubs.cpp
r48574 r48580 680 680 Structure* structure = baseCell->structure(); 681 681 682 if (structure->is UncacheableDictionary()) {682 if (structure->isDictionary()) { 683 683 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); 684 684 return; … … 744 744 Structure* structure = baseCell->structure(); 745 745 746 if (structure->is UncacheableDictionary()) {746 if (structure->isDictionary()) { 747 747 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 748 748 return; … … 1155 1155 if (baseValue.isCell() 1156 1156 && slot.isCacheable() 1157 && !(structure = asCell(baseValue)->structure())->is UncacheableDictionary()1157 && !(structure = asCell(baseValue)->structure())->isDictionary() 1158 1158 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) 1159 1159 && specific … … 1229 1229 if (baseValue.isCell() 1230 1230 && slot.isCacheable() 1231 && !asCell(baseValue)->structure()->is UncacheableDictionary()1231 && !asCell(baseValue)->structure()->isDictionary() 1232 1232 && slot.slotBase() == baseValue) { 1233 1233 … … 1300 1300 CHECK_FOR_EXCEPTION(); 1301 1301 1302 if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->is UncacheableDictionary()) {1302 if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) { 1303 1303 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1304 1304 return JSValue::encode(result); … … 2189 2189 if (globalObject->getPropertySlot(callFrame, ident, slot)) { 2190 2190 JSValue result = slot.getValue(callFrame, ident); 2191 if (slot.isCacheable() && !globalObject->structure()->is UncacheableDictionary() && slot.slotBase() == globalObject) {2191 if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) { 2192 2192 GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex); 2193 2193 if (globalResolveInfo.structure) -
trunk/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
r48573 r48580 39 39 { 40 40 if (!m_object->structure()->isDictionary()) 41 m_object->setStructure(Structure::to CacheableDictionaryTransition(m_object->structure()));41 m_object->setStructure(Structure::toDictionaryTransition(m_object->structure())); 42 42 } 43 43 -
trunk/JavaScriptCore/runtime/JSObject.cpp
r48573 r48580 472 472 { 473 473 size_t offset; 474 if (m_structure->is UncacheableDictionary()) {474 if (m_structure->isDictionary()) { 475 475 offset = m_structure->removePropertyWithoutTransition(propertyName); 476 476 if (offset != WTF::notFound) -
trunk/JavaScriptCore/runtime/Structure.cpp
r48573 r48580 128 128 , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) 129 129 , m_offset(noOffset) 130 , m_ dictionaryKind(NoneDictionaryKind)130 , m_isDictionary(false) 131 131 , m_isPinnedPropertyTable(false) 132 132 , m_hasGetterSetterProperties(false) … … 291 291 void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject) 292 292 { 293 bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || isDictionary());293 bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_isDictionary); 294 294 295 295 if (shouldCache && m_cachedPropertyNameArrayData) { … … 350 350 materializePropertyMapIfNecessary(); 351 351 352 ASSERT( isDictionary());352 ASSERT(m_isDictionary); 353 353 ASSERT(m_propertyTable); 354 354 … … 392 392 PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) 393 393 { 394 ASSERT(!structure-> isDictionary());394 ASSERT(!structure->m_isDictionary); 395 395 ASSERT(structure->typeInfo().type() == ObjectType); 396 396 … … 406 406 PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) 407 407 { 408 ASSERT(!structure-> isDictionary());408 ASSERT(!structure->m_isDictionary); 409 409 ASSERT(structure->typeInfo().type() == ObjectType); 410 410 ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); 411 411 412 412 if (structure->transitionCount() > s_maxTransitionLength) { 413 RefPtr<Structure> transition = to CacheableDictionaryTransition(structure);413 RefPtr<Structure> transition = toDictionaryTransition(structure); 414 414 ASSERT(structure != transition); 415 415 offset = transition->put(propertyName, attributes, specificValue); … … 455 455 PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset) 456 456 { 457 ASSERT(!structure-> isUncacheableDictionary());458 459 RefPtr<Structure> transition = to UncacheableDictionaryTransition(structure);457 ASSERT(!structure->m_isDictionary); 458 459 RefPtr<Structure> transition = toDictionaryTransition(structure); 460 460 461 461 offset = transition->remove(propertyName); … … 555 555 } 556 556 557 PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure , DictionaryKind kind)558 { 559 ASSERT(!structure-> isDictionary());560 557 PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure) 558 { 559 ASSERT(!structure->m_isDictionary); 560 561 561 RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo()); 562 transition->m_ dictionaryKind = kind;562 transition->m_isDictionary = true; 563 563 transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; 564 564 transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; 565 565 566 566 structure->materializePropertyMapIfNecessary(); 567 567 transition->m_propertyTable = structure->copyPropertyTable(); 568 568 transition->m_isPinnedPropertyTable = true; 569 569 570 570 return transition.release(); 571 571 } 572 572 573 PassRefPtr<Structure> Structure::toCacheableDictionaryTransition(Structure* structure)574 {575 return toDictionaryTransition(structure, CachedDictionaryKind);576 }577 578 PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* structure)579 {580 return toDictionaryTransition(structure, UncachedDictionaryKind);581 }582 583 573 PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure) 584 574 { 585 ASSERT(structure-> isDictionary());575 ASSERT(structure->m_isDictionary); 586 576 587 577 // Since dictionary Structures are not shared, and no opcodes specialize … … 592 582 // deleted offsets vector) before transitioning from dictionary. 593 583 if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty()) 594 structure->m_ dictionaryKind = NoneDictionaryKind;584 structure->m_isDictionary = false; 595 585 596 586 return structure; … … 611 601 size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName) 612 602 { 613 ASSERT( isUncacheableDictionary());603 ASSERT(m_isDictionary); 614 604 615 605 materializePropertyMapIfNecessary(); -
trunk/JavaScriptCore/runtime/Structure.h
r48573 r48580 71 71 static PassRefPtr<Structure> addAnonymousSlotsTransition(Structure*, unsigned count); 72 72 static PassRefPtr<Structure> getterSetterTransition(Structure*); 73 static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*); 74 static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*); 73 static PassRefPtr<Structure> toDictionaryTransition(Structure*); 75 74 static PassRefPtr<Structure> fromDictionaryTransition(Structure*); 76 75 … … 83 82 size_t removePropertyWithoutTransition(const Identifier& propertyName); 84 83 void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; } 85 86 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } 87 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } 84 85 bool isDictionary() const { return m_isDictionary; } 88 86 89 87 const TypeInfo& typeInfo() const { return m_typeInfo; } … … 130 128 private: 131 129 Structure(JSValue prototype, const TypeInfo&); 132 133 typedef enum {134 NoneDictionaryKind = 0,135 CachedDictionaryKind = 1,136 UncachedDictionaryKind = 2137 } DictionaryKind;138 static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);139 130 140 131 size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); … … 197 188 signed char m_offset; 198 189 199 unsigned m_dictionaryKind : 2;190 bool m_isDictionary : 1; 200 191 bool m_isPinnedPropertyTable : 1; 201 192 bool m_hasGetterSetterProperties : 1; -
trunk/JavaScriptCore/runtime/StructureChain.cpp
r48573 r48580 52 52 53 53 while (m_vector[i]) { 54 // Both classes of dictionary structure may change arbitrarily so we can't cache them55 54 if (m_vector[i]->isDictionary()) 56 55 return false;
Note:
See TracChangeset
for help on using the changeset viewer.