Changeset 201436 in webkit
- Timestamp:
- May 26, 2016, 3:30:05 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
-
ChangeLog (modified) (1 diff)
-
bytecode/ObjectPropertyConditionSet.cpp (modified) (1 diff)
-
interpreter/Interpreter.cpp (modified) (3 diffs)
-
runtime/BatchedTransitionOptimizer.h (modified) (1 diff)
-
runtime/JSGlobalObject.cpp (modified) (1 diff)
-
runtime/Operations.cpp (modified) (1 diff)
-
runtime/Operations.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r201428 r201436 1 2016-05-26 Geoffrey Garen <ggaren@apple.com> 2 3 REGRESSION: JSBench spends a lot of time transitioning to/from dictionary 4 https://bugs.webkit.org/show_bug.cgi?id=158045 5 6 Reviewed by Saam Barati. 7 8 15% speedup on jsbench-amazon-firefox, possibly 5% speedup overall on jsbench. 9 10 This regression seems to have two parts: 11 12 (1) Transitioning the window object to/from dictionary is more expensive 13 than it used to be to because the window object has lots more properties. 14 The window object has more properties because, for WebIDL compatibility, 15 we reify DOM APIs as properties when you delete. 16 17 (2) DOM prototypes transition to/from dictionary upon creation 18 because, once again for WebIDL compatibility, we reify their static 19 APIs eagerly. 20 21 The solution is to chill out a bit on dictionary transitions. 22 23 * bytecode/ObjectPropertyConditionSet.cpp: Don't flatten a dictionary 24 if we've already done so before. This avoids pathological churn, and it 25 is our idiom in other places. 26 27 * interpreter/Interpreter.cpp: 28 (JSC::Interpreter::execute): Do flatten the global object unconditionally 29 if it is an uncacheable dictionary because the global object is super 30 important. 31 32 * runtime/BatchedTransitionOptimizer.h: 33 (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): 34 (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): Deleted. 35 Don't transition away from dictionary after a batched set of property 36 puts because normal dictionaries are cacheable and that's a perfectly 37 fine state to be in -- and the transition is expensive. 38 39 * runtime/JSGlobalObject.cpp: 40 (JSC::JSGlobalObject::init): Do start the global object out as a cacheable 41 dictionary because it will inevitably have enough properties to become 42 a dictionary. 43 44 * runtime/Operations.h: 45 (JSC::normalizePrototypeChain): Same as ObjectPropertyConditionSet.cpp. 46 1 47 2016-05-25 Geoffrey Garen <ggaren@apple.com> 2 48 -
trunk/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp
r201363 r201436 264 264 structure = object->structure(vm); 265 265 266 // Since we're accessing a prototype repeatedly, it's a good bet that it should not be267 // treated as a dictionary.268 266 if (structure->isDictionary()) { 269 267 if (concurrency == MainThread) { 268 if (structure->hasBeenFlattenedBefore()) { 269 if (verbose) 270 dataLog("Dictionary has been flattened before, so invalid.\n"); 271 return ObjectPropertyConditionSet::invalid(); 272 } 270 273 if (verbose) 271 274 dataLog("Flattening ", pointerDump(structure)); -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r201328 r201436 939 939 return throwTerminatedExecutionException(callFrame); 940 940 941 if (scope->structure()->isUncacheableDictionary()) 942 scope->flattenDictionaryObject(vm); 943 941 944 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. 942 945 … … 1187 1190 } 1188 1191 1192 if (variableObject->structure()->isUncacheableDictionary()) 1193 variableObject->flattenDictionaryObject(vm); 1194 1189 1195 if (numVariables || numFunctions) { 1190 1196 BatchedTransitionOptimizer optimizer(vm, variableObject); … … 1243 1249 if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) 1244 1250 return throwTerminatedExecutionException(callFrame); 1251 1252 if (scope->structure()->isUncacheableDictionary()) 1253 scope->flattenDictionaryObject(vm); 1245 1254 1246 1255 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. -
trunk/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
r169703 r201436 36 36 public: 37 37 BatchedTransitionOptimizer(VM& vm, JSObject* object) 38 : m_vm(&vm)39 , m_object(object)40 38 { 41 if (! m_object->structure(vm)->isDictionary())42 m_object->convertToDictionary(vm);39 if (!object->structure(vm)->isDictionary()) 40 object->convertToDictionary(vm); 43 41 } 44 45 ~BatchedTransitionOptimizer()46 {47 if (m_object->structure()->isDictionary())48 m_object->flattenDictionaryObject(*m_vm);49 }50 51 private:52 VM* m_vm;53 JSObject* m_object;54 42 }; 55 43 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r201340 r201436 320 320 ASSERT(vm.currentThreadIsHoldingAPILock()); 321 321 322 Base::setStructure(vm, Structure::toCacheableDictionaryTransition(vm, structure())); 323 322 324 JSGlobalObject::globalExec()->init(0, 0, CallFrame::noCaller(), 0, 0); 323 325 -
trunk/Source/JavaScriptCore/runtime/Operations.cpp
r197614 r201436 121 121 } 122 122 123 size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure) 124 { 125 VM& vm = callFrame->vm(); 126 size_t count = 0; 127 while (1) { 128 if (structure->isProxy()) 129 return InvalidPrototypeChain; 130 JSValue v = structure->prototypeForLookup(callFrame); 131 if (v.isNull()) 132 return count; 133 134 JSCell* base = v.asCell(); 135 structure = base->structure(vm); 136 if (structure->isDictionary()) { 137 if (structure->hasBeenFlattenedBefore()) 138 return InvalidPrototypeChain; 139 structure->flattenDictionaryStructure(vm, asObject(base)); 140 } 141 142 ++count; 143 } 144 } 145 123 146 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/Operations.h
r187780 r201436 28 28 29 29 namespace JSC { 30 31 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max()) 30 32 31 33 NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); … … 34 36 bool jsIsObjectTypeOrNull(CallFrame*, JSValue); 35 37 bool jsIsFunctionType(JSValue); 38 size_t normalizePrototypeChain(CallFrame*, Structure*); 36 39 37 40 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) … … 193 196 } 194 197 195 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())196 197 inline size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure)198 {199 VM& vm = callFrame->vm();200 size_t count = 0;201 while (1) {202 if (structure->isProxy())203 return InvalidPrototypeChain;204 JSValue v = structure->prototypeForLookup(callFrame);205 if (v.isNull())206 return count;207 208 JSCell* base = v.asCell();209 structure = base->structure(vm);210 // Since we're accessing a prototype in a loop, it's a good bet that it211 // should not be treated as a dictionary.212 if (structure->isDictionary())213 structure->flattenDictionaryStructure(vm, asObject(base));214 215 ++count;216 }217 }218 219 198 } // namespace JSC 220 199
Note:
See TracChangeset
for help on using the changeset viewer.