Changeset 36316 in webkit for trunk/JavaScriptCore
- Timestamp:
- Sep 10, 2008, 1:42:43 AM (17 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r36315 r36316 1 2008-09-10 Maciej Stachowiak <[email protected]> 2 3 Reviewed by Oliver. 4 5 - enable polymorphic inline caching of properties of primitives 6 7 1.012x speedup on SunSpider. 8 9 We create special structure IDs for JSString and 10 JSNumberCell. Unlike normal structure IDs, these cannot hold the 11 true prototype. Due to JS autoboxing semantics, the prototype used 12 when looking up string or number properties depends on the lexical 13 global object of the call site, not the creation site. Thus we 14 enable StructureIDs to handle this quirk for primitives. 15 16 Everything else should be straightforward. 17 18 * VM/CTI.cpp: 19 (JSC::CTI::privateCompileGetByIdProto): 20 (JSC::CTI::privateCompileGetByIdChain): 21 * VM/CTI.h: 22 (JSC::CTI::compileGetByIdProto): 23 (JSC::CTI::compileGetByIdChain): 24 * VM/JSPropertyNameIterator.h: 25 (JSC::JSPropertyNameIterator::JSPropertyNameIterator): 26 * VM/Machine.cpp: 27 (JSC::Machine::Machine): 28 (JSC::cachePrototypeChain): 29 (JSC::Machine::tryCachePutByID): 30 (JSC::Machine::tryCacheGetByID): 31 (JSC::Machine::privateExecute): 32 (JSC::Machine::tryCTICachePutByID): 33 (JSC::Machine::tryCTICacheGetByID): 34 * kjs/GetterSetter.h: 35 (JSC::GetterSetter::GetterSetter): 36 * kjs/JSCell.h: 37 * kjs/JSGlobalData.cpp: 38 (JSC::JSGlobalData::JSGlobalData): 39 * kjs/JSGlobalData.h: 40 * kjs/JSGlobalObject.h: 41 (JSC::StructureID::prototypeForLookup): 42 * kjs/JSNumberCell.h: 43 (JSC::JSNumberCell::JSNumberCell): 44 (JSC::jsNumberCell): 45 * kjs/JSObject.h: 46 (JSC::JSObject::prototype): 47 * kjs/JSString.cpp: 48 (JSC::jsString): 49 (JSC::jsSubstring): 50 (JSC::jsOwnedString): 51 * kjs/JSString.h: 52 (JSC::JSString::JSString): 53 (JSC::JSString::): 54 (JSC::jsSingleCharacterString): 55 (JSC::jsSingleCharacterSubstring): 56 (JSC::jsNontrivialString): 57 * kjs/SmallStrings.cpp: 58 (JSC::SmallStrings::createEmptyString): 59 (JSC::SmallStrings::createSingleCharacterString): 60 * kjs/StructureID.cpp: 61 (JSC::StructureID::StructureID): 62 (JSC::StructureID::addPropertyTransition): 63 (JSC::StructureID::getterSetterTransition): 64 (JSC::StructureIDChain::StructureIDChain): 65 * kjs/StructureID.h: 66 (JSC::StructureID::create): 67 (JSC::StructureID::storedPrototype): 68 1 69 2008-09-09 Joerg Bornemann <[email protected]> 2 70 -
trunk/JavaScriptCore/VM/CTI.cpp
r36311 r36316 1673 1673 } 1674 1674 1675 void* CTI::privateCompileGetByIdProto( StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)1675 void* CTI::privateCompileGetByIdProto(ExecState* exec, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset) 1676 1676 { 1677 1677 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a StructureID that is 1678 1678 // referencing the prototype object - let's speculatively load it's table nice and early!) 1679 JSObject* protoObject = static_cast<JSObject*>(structureID->prototype ());1679 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec)); 1680 1680 OwnArrayPtr<JSValue*>* protoPropertyStorage = &protoObject->m_propertyStorage; 1681 1681 m_jit.movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx); … … 1709 1709 } 1710 1710 1711 void* CTI::privateCompileGetByIdChain( StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)1711 void* CTI::privateCompileGetByIdChain(ExecState* exec, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset) 1712 1712 { 1713 1713 ASSERT(count); … … 1725 1725 JSCell* protoObject = 0; 1726 1726 for (unsigned i = 0; i<count; ++i) { 1727 protoObject = static_cast<JSCell*>(currStructureID->prototype ());1727 protoObject = static_cast<JSCell*>(currStructureID->prototypeForLookup(exec)); 1728 1728 currStructureID = chainEntries[i].get(); 1729 1729 -
trunk/JavaScriptCore/VM/CTI.h
r36311 r36316 246 246 { 247 247 CTI cti(machine, exec, codeBlock); 248 return cti.privateCompileGetByIdProto( structureID, prototypeStructureID, cachedOffset);248 return cti.privateCompileGetByIdProto(exec, structureID, prototypeStructureID, cachedOffset); 249 249 } 250 250 … … 252 252 { 253 253 CTI cti(machine, exec, codeBlock); 254 return cti.privateCompileGetByIdChain( structureID, chain, count, cachedOffset);254 return cti.privateCompileGetByIdChain(exec, structureID, chain, count, cachedOffset); 255 255 } 256 256 … … 289 289 void privateCompile(); 290 290 void* privateCompileGetByIdSelf(StructureID*, size_t cachedOffset); 291 void* privateCompileGetByIdProto( StructureID*, StructureID* prototypeStructureID, size_t cachedOffset);292 void* privateCompileGetByIdChain( StructureID*, StructureIDChain*, size_t count, size_t cachedOffset);291 void* privateCompileGetByIdProto(ExecState*, StructureID*, StructureID* prototypeStructureID, size_t cachedOffset); 292 void* privateCompileGetByIdChain(ExecState*, StructureID*, StructureIDChain*, size_t count, size_t cachedOffset); 293 293 void* privateCompilePutByIdReplace(StructureID*, size_t cachedOffset); 294 294 void* privateArrayLengthTrampoline(); -
trunk/JavaScriptCore/VM/JSPropertyNameIterator.h
r36263 r36316 67 67 68 68 inline JSPropertyNameIterator::JSPropertyNameIterator(JSObject* object, Identifier* propertyNames, size_t numProperties) 69 : m_object(object) 69 : JSCell(0) 70 , m_object(object) 70 71 , m_propertyNames(propertyNames) 71 72 , m_position(propertyNames) -
trunk/JavaScriptCore/VM/Machine.cpp
r36267 r36316 545 545 static_cast<JSCell*>(jsArray)->~JSCell(); 546 546 547 JSString* jsString = new (storage) JSString( "");547 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack); 548 548 m_jsStringVptr = jsString->vptr(); 549 549 static_cast<JSCell*>(jsString)->~JSCell(); … … 1106 1106 } 1107 1107 1108 StructureIDChain* cachePrototypeChain(StructureID* structureID)1109 { 1110 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototype ())->structureID());1108 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID) 1109 { 1110 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototypeForLookup(exec))->structureID()); 1111 1111 structureID->setCachedPrototypeChain(chain.release()); 1112 1112 return structureID->cachedPrototypeChain(); … … 1136 1136 JSCell* baseCell = static_cast<JSCell*>(baseValue); 1137 1137 StructureID* structureID = baseCell->structureID(); 1138 1139 // FIXME: Remove this !structureID check once all objects have StructureIDs.1140 if (!structureID) {1141 vPC[0] = getOpcode(op_put_by_id_generic);1142 return;1143 }1144 1138 1145 1139 if (structureID->isDictionary()) { … … 1211 1205 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID(); 1212 1206 1213 // FIXME: Remove this !structureID check once all JSCells have StructureIDs.1214 if (!structureID) {1215 vPC[0] = getOpcode(op_get_by_id_generic);1216 return;1217 }1218 1219 1207 if (structureID->isDictionary()) { 1220 1208 vPC[0] = getOpcode(op_get_by_id_generic); … … 1246 1234 } 1247 1235 1248 if (slot.slotBase() == structureID->prototype ()) {1236 if (slot.slotBase() == structureID->prototypeForLookup(exec)) { 1249 1237 ASSERT(slot.slotBase()->isObject()); 1250 1238 … … 1270 1258 JSObject* o = static_cast<JSObject*>(baseValue); 1271 1259 while (slot.slotBase() != o) { 1272 JSValue* v = o->structureID()->prototype ();1260 JSValue* v = o->structureID()->prototypeForLookup(exec); 1273 1261 1274 1262 // If we didn't find base in baseValue's prototype chain, then baseValue … … 1294 1282 StructureIDChain* chain = structureID->cachedPrototypeChain(); 1295 1283 if (!chain) 1296 chain = cachePrototypeChain( structureID);1284 chain = cachePrototypeChain(exec, structureID); 1297 1285 1298 1286 vPC[0] = getOpcode(op_get_by_id_chain); … … 2265 2253 2266 2254 if (LIKELY(baseCell->structureID() == structureID)) { 2267 ASSERT(structureID->prototype ()->isObject());2268 JSObject* protoObject = static_cast<JSObject*>(structureID->prototype ());2255 ASSERT(structureID->prototypeForLookup(exec)->isObject()); 2256 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec)); 2269 2257 StructureID* protoStructureID = vPC[5].u.structureID; 2270 2258 … … 2306 2294 while (1) { 2307 2295 ASSERT(baseCell->isObject()); 2308 JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototype ());2296 JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototypeForLookup(exec)); 2309 2297 if (UNLIKELY(baseObject->structureID() != (*it).get())) 2310 2298 break; … … 2338 2326 2339 2327 Identifier& ident = codeBlock->identifiers[property]; 2328 2340 2329 JSValue* baseValue = r[base].jsValue(exec); 2341 2330 PropertySlot slot(baseValue); … … 3550 3539 StructureID* structureID = baseCell->structureID(); 3551 3540 3552 // FIXME: Remove this !structureID check once all objects have StructureIDs.3553 if (!structureID) {3554 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);3555 return;3556 }3557 3558 3541 if (structureID->isDictionary()) { 3559 3542 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); … … 3625 3608 JSCell* baseCell = static_cast<JSCell*>(baseValue); 3626 3609 StructureID* structureID = baseCell->structureID(); 3627 3628 // FIXME: Remove this !structureID check once all JSCells have StructureIDs.3629 if (!structureID) {3630 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);3631 return;3632 }3633 3610 3634 3611 if (structureID->isDictionary()) { … … 3656 3633 } 3657 3634 3658 if (slot.slotBase() == structureID->prototype ()) {3635 if (slot.slotBase() == structureID->prototypeForLookup(exec)) { 3659 3636 ASSERT(slot.slotBase()->isObject()); 3660 3637 … … 3682 3659 JSObject* o = static_cast<JSObject*>(baseValue); 3683 3660 while (slot.slotBase() != o) { 3684 JSValue* v = o->structureID()->prototype ();3661 JSValue* v = o->structureID()->prototypeForLookup(exec); 3685 3662 3686 3663 // If we didn't find slotBase in baseValue's prototype chain, then baseValue … … 3707 3684 StructureIDChain* chain = structureID->cachedPrototypeChain(); 3708 3685 if (!chain) 3709 chain = cachePrototypeChain( structureID);3686 chain = cachePrototypeChain(exec, structureID); 3710 3687 3711 3688 vPC[0] = getOpcode(op_get_by_id_chain); -
trunk/JavaScriptCore/kjs/GetterSetter.h
r36263 r36316 35 35 public: 36 36 GetterSetter() 37 : m_getter(0) 37 : JSCell(0) 38 , m_getter(0) 38 39 , m_setter(0) 39 40 { -
trunk/JavaScriptCore/kjs/JSCell.h
r36263 r36316 41 41 friend class CTI; 42 42 private: 43 JSCell();44 43 JSCell(StructureID*); 45 44 virtual ~JSCell(); … … 109 108 }; 110 109 111 inline JSCell::JSCell()112 : m_structureID(0)113 {114 }115 116 110 inline JSCell::JSCell(StructureID* structureID) 117 111 : m_structureID(structureID) -
trunk/JavaScriptCore/kjs/JSGlobalData.cpp
r36263 r36316 78 78 #endif 79 79 , nullProtoStructureID(StructureID::create(jsNull())) 80 , stringStructureID(StructureID::create(jsNull(), StringType)) 81 , numberStructureID(StructureID::create(jsNull(), NumberType)) 80 82 , identifierTable(createIdentifierTable()) 81 83 , propertyNames(new CommonIdentifiers(this)) -
trunk/JavaScriptCore/kjs/JSGlobalData.h
r36263 r36316 75 75 76 76 RefPtr<StructureID> nullProtoStructureID; 77 RefPtr<StructureID> stringStructureID; 78 RefPtr<StructureID> numberStructureID; 77 79 78 80 IdentifierTable* identifierTable; -
trunk/JavaScriptCore/kjs/JSGlobalObject.h
r36263 r36316 25 25 #include "JSGlobalData.h" 26 26 #include "JSVariableObject.h" 27 #include "NumberPrototype.h" 28 #include "StringPrototype.h" 27 29 #include <wtf/HashSet.h> 28 30 #include <wtf/OwnPtr.h> … … 294 296 } 295 297 298 inline JSValue* StructureID::prototypeForLookup(ExecState* exec) { 299 if (m_type == ObjectType) 300 return m_prototype; 301 302 if (m_type == StringType) 303 return exec->lexicalGlobalObject()->stringPrototype(); 304 305 ASSERT(m_type == NumberType); 306 return exec->lexicalGlobalObject()->numberPrototype(); 307 } 308 296 309 } // namespace JSC 297 310 -
trunk/JavaScriptCore/kjs/JSNumberCell.h
r36263 r36316 71 71 72 72 private: 73 JSNumberCell(double value) 74 : m_value(value) 73 JSNumberCell(ExecState* exec, double value) 74 : JSCell(exec->globalData().numberStructureID.get()) 75 , m_value(value) 75 76 { 76 77 } … … 90 91 inline JSValue* jsNumberCell(ExecState* exec, double d) 91 92 { 92 return new (exec) JSNumberCell( d);93 return new (exec) JSNumberCell(exec, d); 93 94 } 94 95 -
trunk/JavaScriptCore/kjs/JSObject.h
r36314 r36316 214 214 inline JSValue* JSObject::prototype() const 215 215 { 216 return m_structureID-> prototype();216 return m_structureID->storedPrototype(); 217 217 } 218 218 -
trunk/JavaScriptCore/kjs/JSString.cpp
r36263 r36316 126 126 return exec->globalData().smallStrings.singleCharacterString(exec, c); 127 127 } 128 return new (exec) JSString( s);128 return new (exec) JSString(exec, s); 129 129 } 130 130 … … 141 141 return exec->globalData().smallStrings.singleCharacterString(exec, c); 142 142 } 143 return new (exec) JSString( UString::Rep::create(s.rep(), offset, length));143 return new (exec) JSString(exec, UString::Rep::create(s.rep(), offset, length)); 144 144 } 145 145 … … 154 154 return exec->globalData().smallStrings.singleCharacterString(exec, c); 155 155 } 156 return new (exec) JSString( s, JSString::HasOtherOwner);156 return new (exec) JSString(exec, s, JSString::HasOtherOwner); 157 157 } 158 158 -
trunk/JavaScriptCore/kjs/JSString.h
r36263 r36316 53 53 class JSString : public JSCell { 54 54 friend class CTI; 55 friend class Machine; 55 56 56 57 public: 57 JSString(const UString& value) 58 : m_value(value) 58 JSString(ExecState* exec, const UString& value) 59 : JSCell(exec->globalData().stringStructureID.get()) 60 , m_value(value) 59 61 { 60 62 Heap::heap(this)->reportExtraMemoryCost(value.cost()); … … 62 64 63 65 enum HasOtherOwnerType { HasOtherOwner }; 64 JSString(const UString& value, HasOtherOwnerType) 65 : m_value(value) 66 JSString(ExecState* exec, const UString& value, HasOtherOwnerType) 67 : JSCell(exec->globalData().stringStructureID.get()) 68 , m_value(value) 66 69 { 67 70 } 68 JSString(PassRefPtr<UString::Rep> value, HasOtherOwnerType) 69 : m_value(value) 71 JSString(ExecState* exec, PassRefPtr<UString::Rep> value, HasOtherOwnerType) 72 : JSCell(exec->globalData().stringStructureID.get()) 73 , m_value(value) 70 74 { 71 75 } … … 80 84 81 85 private: 86 enum VPtrStealingHackType { VPtrStealingHack }; 87 JSString(VPtrStealingHackType) 88 : JSCell(0) 89 { 90 } 82 91 virtual bool isString() const; 83 92 … … 109 118 if (c <= 0xFF) 110 119 return exec->globalData().smallStrings.singleCharacterString(exec, c); 111 return new (exec) JSString( UString(&c, 1));120 return new (exec) JSString(exec, UString(&c, 1)); 112 121 } 113 122 … … 118 127 if (c <= 0xFF) 119 128 return exec->globalData().smallStrings.singleCharacterString(exec, c); 120 return new (exec) JSString( UString::Rep::create(s.rep(), offset, 1));129 return new (exec) JSString(exec, UString::Rep::create(s.rep(), offset, 1)); 121 130 } 122 131 … … 126 135 ASSERT(s[0]); 127 136 ASSERT(s[1]); 128 return new (exec) JSString( s);137 return new (exec) JSString(exec, s); 129 138 } 130 139 … … 132 141 { 133 142 ASSERT(s.size() > 1); 134 return new (exec) JSString( s);143 return new (exec) JSString(exec, s); 135 144 } 136 145 -
trunk/JavaScriptCore/kjs/SmallStrings.cpp
r36263 r36316 91 91 { 92 92 ASSERT(!m_emptyString); 93 m_emptyString = new (exec) JSString( "", JSString::HasOtherOwner);93 m_emptyString = new (exec) JSString(exec, "", JSString::HasOtherOwner); 94 94 } 95 95 … … 99 99 m_storage.set(new SmallStringsStorage); 100 100 ASSERT(!m_singleCharacterStrings[character]); 101 m_singleCharacterStrings[character] = new (exec) JSString( m_storage->rep(character), JSString::HasOtherOwner);101 m_singleCharacterStrings[character] = new (exec) JSString(exec, m_storage->rep(character), JSString::HasOtherOwner); 102 102 } 103 103 -
trunk/JavaScriptCore/kjs/StructureID.cpp
r36285 r36316 35 35 namespace JSC { 36 36 37 StructureID::StructureID(JSValue* prototype)37 StructureID::StructureID(JSValue* prototype, JSType type) 38 38 : m_isDictionary(false) 39 , m_type(type) 39 40 , m_prototype(prototype) 40 41 , m_cachedPrototypeChain(0) … … 50 51 { 51 52 ASSERT(!structureID->m_isDictionary); 53 ASSERT(structureID->m_type == ObjectType); 52 54 53 55 if (StructureID* existingTransition = structureID->m_transitionTable.get(make_pair(propertyName.ustring().rep(), attributes))) { … … 114 116 PassRefPtr<StructureID> StructureID::getterSetterTransition(StructureID* structureID) 115 117 { 116 RefPtr<StructureID> transition = create(structureID-> prototype());118 RefPtr<StructureID> transition = create(structureID->storedPrototype()); 117 119 transition->m_transitionCount = structureID->m_transitionCount + 1; 118 120 transition->m_propertyMap = structureID->m_propertyMap; … … 133 135 134 136 StructureID* tmp = structureID; 135 while (!tmp-> prototype()->isNull()) {137 while (!tmp->storedPrototype()->isNull()) { 136 138 ++size; 137 tmp = static_cast<JSCell*>(tmp-> prototype())->structureID();139 tmp = static_cast<JSCell*>(tmp->storedPrototype())->structureID(); 138 140 } 139 141 … … 143 145 for (i = 0; i < size - 1; ++i) { 144 146 m_vector[i] = structureID; 145 structureID = static_cast<JSObject*>(structureID-> prototype())->structureID();147 structureID = static_cast<JSObject*>(structureID->storedPrototype())->structureID(); 146 148 } 147 149 m_vector[i] = structureID; -
trunk/JavaScriptCore/kjs/StructureID.h
r36285 r36316 27 27 #define StructureID_h 28 28 29 #include "JSType.h" 29 30 #include "JSValue.h" 30 31 #include "PropertyMap.h" … … 72 73 class StructureID : public RefCounted<StructureID> { 73 74 public: 74 static PassRefPtr<StructureID> create(JSValue* prototype )75 static PassRefPtr<StructureID> create(JSValue* prototype, JSType type = ObjectType) 75 76 { 76 return adoptRef(new StructureID(prototype ));77 return adoptRef(new StructureID(prototype, type)); 77 78 } 78 79 … … 93 94 bool isDictionary() const { return m_isDictionary; } 94 95 95 JSValue* prototype() const { return m_prototype; } 96 96 JSValue* storedPrototype() const { return m_prototype; } 97 JSValue* prototypeForLookup(ExecState*); 98 97 99 void setCachedPrototypeChain(PassRefPtr<StructureIDChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } 98 100 StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); } … … 105 107 typedef HashMap<TransitionTableKey, StructureID*, TransitionTableHash, TransitionTableHashTraits> TransitionTable; 106 108 107 StructureID(JSValue* prototype );109 StructureID(JSValue* prototype, JSType); 108 110 109 111 static const size_t s_maxTransitionLength = 64; 110 112 111 113 bool m_isDictionary; 114 JSType m_type; 112 115 113 116 JSValue* m_prototype;
Note:
See TracChangeset
for help on using the changeset viewer.