Changeset 234022 in webkit
- Timestamp:
- Jul 19, 2018 9:47:51 PM (6 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r233999 r234022 1 2018-07-19 Saam Barati <sbarati@apple.com> 2 3 Conservatively make Object.assign's fast path do a two phase protocol of loading everything then storing everything to try to prevent a crash 4 https://bugs.webkit.org/show_bug.cgi?id=187836 5 <rdar://problem/42409527> 6 7 Reviewed by Mark Lam. 8 9 We have crash reports that we're crashing on source->getDirect in Object.assign's 10 fast path. Mark investigated this and determined we end up with a nullptr for 11 butterfly. This is curious, because source's Structure indicated that it has 12 out of line properties. My leading hypothesis for this at the moment is a bit 13 handwavy, but it's essentially: 14 - We end up firing a watchpoint when assigning to the target (this can happen 15 if a watchpoint was set up for storing to that particular field) 16 - When we fire that watchpoint, we end up doing some kind work on the source, 17 perhaps causing it to flattenDictionaryStructure. Therefore, we end up 18 mutating source. 19 20 I'm not super convinced this is what we're running into, but just by reading 21 the code, I think it needs to be something similar to this. Seeing if this change 22 fixes the crasher will give us good data to determine if something like this is 23 happening or if the bug is something else entirely. 24 25 * runtime/ObjectConstructor.cpp: 26 (JSC::objectConstructorAssign): 27 1 28 2018-07-19 Commit Queue <commit-queue@webkit.org> 2 29 -
trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
r233122 r234022 319 319 } 320 320 321 auto canPerformFastPropertyEnumerationForObjectAssign = [] (Structure* structure) { 322 if (structure->typeInfo().overridesGetOwnPropertySlot()) 323 return false; 324 if (structure->typeInfo().overridesGetPropertyNames()) 325 return false; 326 // FIXME: Indexed properties can be handled. 327 // https://bugs.webkit.org/show_bug.cgi?id=185358 328 if (hasIndexedProperties(structure->indexingType())) 329 return false; 330 if (structure->hasGetterSetterProperties()) 331 return false; 332 if (structure->isUncacheableDictionary()) 333 return false; 334 // Cannot perform fast [[Put]] to |target| if the property names of the |source| contain "__proto__". 335 if (structure->hasUnderscoreProtoPropertyExcludingOriginalProto()) 336 return false; 337 return true; 338 }; 339 340 Structure* structure = source->structure(vm); 341 if (canPerformFastPropertyEnumerationForObjectAssign(structure)) { 342 // |source| Structure does not have any getters. And target can perform fast put. 343 // So enumerating properties and putting properties are non observable. 344 structure->forEachProperty(vm, [&] (const PropertyMapEntry& entry) -> bool { 345 if (entry.attributes & PropertyAttribute::DontEnum) 321 bool canDoFastPath; 322 Vector<RefPtr<UniquedStringImpl>, 8> properties; 323 MarkedArgumentBuffer values; 324 { 325 auto canPerformFastPropertyEnumerationForObjectAssign = [] (Structure* structure) { 326 if (structure->typeInfo().overridesGetOwnPropertySlot()) 327 return false; 328 if (structure->typeInfo().overridesGetPropertyNames()) 329 return false; 330 // FIXME: Indexed properties can be handled. 331 // https://bugs.webkit.org/show_bug.cgi?id=185358 332 if (hasIndexedProperties(structure->indexingType())) 333 return false; 334 if (structure->hasGetterSetterProperties()) 335 return false; 336 if (structure->isUncacheableDictionary()) 337 return false; 338 // Cannot perform fast [[Put]] to |target| if the property names of the |source| contain "__proto__". 339 if (structure->hasUnderscoreProtoPropertyExcludingOriginalProto()) 340 return false; 341 return true; 342 }; 343 344 Structure* structure = source->structure(vm); 345 canDoFastPath = canPerformFastPropertyEnumerationForObjectAssign(structure); 346 if (canDoFastPath) { 347 // |source| Structure does not have any getters. And target can perform fast put. 348 // So enumerating properties and putting properties are non observable. 349 350 // FIXME: It doesn't seem like we should have to do this in two phases, but 351 // we're running into crashes where it appears that source is transitioning 352 // under us, and even ends up in a state where it has a null butterfly. My 353 // leading hypothesis here is that we fire some value replacement watchpoint 354 // that ends up transitioning the structure underneath us. 355 // https://bugs.webkit.org/show_bug.cgi?id=187837 356 357 structure->forEachProperty(vm, [&] (const PropertyMapEntry& entry) -> bool { 358 if (entry.attributes & PropertyAttribute::DontEnum) 359 return true; 360 361 PropertyName propertyName(entry.key); 362 if (propertyName.isPrivateName()) 363 return true; 364 365 properties.append(entry.key); 366 values.appendWithCrashOnOverflow(source->getDirect(entry.offset)); 367 346 368 return true; 347 348 PropertyName propertyName(entry.key); 349 if (propertyName.isPrivateName()) 350 return true; 351 369 }); 370 } 371 } 372 373 if (canDoFastPath) { 374 for (size_t i = 0; i < properties.size(); ++i) { 352 375 // FIXME: We could put properties in a batching manner to accelerate Object.assign more. 353 376 // https://bugs.webkit.org/show_bug.cgi?id=185358 354 377 PutPropertySlot putPropertySlot(target, true); 355 target->putOwnDataProperty(vm, propert yName, source->getDirect(entry.offset), putPropertySlot);356 return true;357 }); 378 target->putOwnDataProperty(vm, properties[i].get(), values.at(i), putPropertySlot); 379 } 380 358 381 continue; 359 382 }
Note: See TracChangeset
for help on using the changeset viewer.