Changeset 287800 in webkit
- Timestamp:
- Jan 7, 2022, 5:52:18 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 5 edited
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/microbenchmarks/array-slice-call-cloned-arguments.js (added)
-
JSTests/stress/array-slice-beyond-length.js (added)
-
JSTests/stress/array-slice-length-lookup.js (added)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/runtime/ArrayPrototype.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/JSArray.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/runtime/JSArray.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r287738 r287800 1 2022-01-07 Alexey Shvayka <ashvayka@apple.com> 2 3 Expand the set of objects we take JSArray::fastSlice() path for 4 https://bugs.webkit.org/show_bug.cgi?id=234539 5 6 Reviewed by Yusuke Suzuki. 7 8 * microbenchmarks/array-slice-call-cloned-arguments.js: Added. 9 * stress/array-slice-beyond-length.js: Added. 10 * stress/array-slice-length-lookup.js: Added. 11 1 12 2022-01-06 Saam Barati <sbarati@apple.com> 2 13 -
trunk/Source/JavaScriptCore/ChangeLog
r287784 r287800 1 2022-01-07 Alexey Shvayka <ashvayka@apple.com> 2 3 Expand the set of objects we take JSArray::fastSlice() path for 4 https://bugs.webkit.org/show_bug.cgi?id=234539 5 6 Reviewed by Yusuke Suzuki. 7 8 Currently, Array.prototype's slice() / splice() methods take a fast path only for 9 JSArray source objects. With this change, gcSafeMemcpy-based path is taken for any 10 object with ordinary getOwnPropertySlotByIndex() method, which speeds up the common 11 case of `[].slice.call(arguments)` by 140% (in strict mode only, see ClonedArguments). 12 13 Also, once is https://webkit.org/b/234538 resolved, calling Array.prototype.slice() 14 on a static NodeList, which is a common idiom to acquire map() / filter() methods, 15 will become faster as well. 16 17 This patch was thoroughly evaluated to be spec-perfect and memory-safe: 18 19 - indexing mode check and holesMustForwardToPrototype() guarantee that there 20 are no observable userland code to be invoked; 21 - fastSlice() signature is upgraded to uint64_t so `nullptr` is returned in case 22 of large "length", resulting in a RangeError being thrown on the slow path; 23 - to handle the case of source array being shrinked after "length" lookup (see r175420), 24 OOB read check is moved to JSArray::fastSlice() and refined to rely on vectorLength() 25 so the double "length" lookup is avoided (added a test for this). 26 27 All this (and more) is well covered by the test262 suite. 28 29 This change improves Speedometer2/EmberJS-Debug-TodoMVC score by 0.5%: although the test 30 is slow on its own, `[].slice.call(arguments)` is performed ~56k times per run. 31 32 * runtime/ArrayPrototype.cpp: 33 (JSC::JSC_DEFINE_HOST_FUNCTION): 34 * runtime/JSArray.cpp: 35 (JSC::JSArray::fastSlice): 36 * runtime/JSArray.h: 37 1 38 2022-01-07 Tim Horton <timothy_horton@apple.com> 2 39 -
trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
r287561 r287800 1140 1140 return { }; 1141 1141 1142 bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == toLength(globalObject, thisObj); 1143 RETURN_IF_EXCEPTION(scope, { }); 1144 if (LIKELY(okToDoFastPath)) { 1145 if (JSArray* result = asArray(thisObj)->fastSlice(globalObject, static_cast<uint32_t>(begin), static_cast<uint32_t>(end - begin))) 1142 if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath)) { 1143 if (JSArray* result = JSArray::fastSlice(globalObject, thisObj, begin, end - begin)) 1146 1144 return JSValue::encode(result); 1147 1145 } … … 1236 1234 1237 1235 JSObject* result = nullptr; 1238 bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == toLength(globalObject, thisObj); 1239 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1240 if (LIKELY(okToDoFastPath)) 1241 result = asArray(thisObj)->fastSlice(globalObject, static_cast<uint32_t>(actualStart), static_cast<uint32_t>(actualDeleteCount)); 1236 if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath)) 1237 result = JSArray::fastSlice(globalObject, thisObj, actualStart, actualDeleteCount); 1242 1238 1243 1239 if (!result) { -
trunk/Source/JavaScriptCore/runtime/JSArray.cpp
r286572 r287800 726 726 } 727 727 728 JSArray* JSArray::fastSlice(JSGlobalObject* globalObject, unsigned startIndex, unsigned count) 729 { 730 VM& vm = globalObject->vm(); 731 732 ensureWritable(vm); 733 734 auto arrayType = indexingMode(); 728 JSArray* JSArray::fastSlice(JSGlobalObject* globalObject, JSObject* source, uint64_t startIndex, uint64_t count) 729 { 730 VM& vm = globalObject->vm(); 731 732 // FIXME: Avoid converting the source from CoW since we aren't modifying it. 733 // https://bugs.webkit.org/show_bug.cgi?id=234990 734 source->ensureWritable(vm); 735 736 Structure* sourceStructure = source->structure(vm); 737 if (sourceStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) 738 return nullptr; 739 740 auto arrayType = source->indexingMode() | IsArray; 735 741 switch (arrayType) { 736 742 case ArrayWithDouble: 737 743 case ArrayWithInt32: 738 744 case ArrayWithContiguous: { 739 if (count >= MIN_SPARSE_ARRAY_INDEX || structure(vm)->holesMustForwardToPrototype(vm, this)) 745 if (count >= MIN_SPARSE_ARRAY_INDEX || sourceStructure->holesMustForwardToPrototype(vm, source)) 746 return nullptr; 747 748 if (startIndex + count > source->butterfly()->vectorLength()) 740 749 return nullptr; 741 750 … … 746 755 ASSERT(!globalObject->isHavingABadTime()); 747 756 ObjectInitializationScope scope(vm); 748 JSArray* resultArray = JSArray::tryCreateUninitializedRestricted(scope, resultStructure, count);757 JSArray* resultArray = JSArray::tryCreateUninitializedRestricted(scope, resultStructure, static_cast<uint32_t>(count)); 749 758 if (UNLIKELY(!resultArray)) 750 759 return nullptr; … … 752 761 auto& resultButterfly = *resultArray->butterfly(); 753 762 if (arrayType == ArrayWithDouble) 754 gcSafeMemcpy(resultButterfly.contiguousDouble().data(), butterfly()->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);763 gcSafeMemcpy(resultButterfly.contiguousDouble().data(), source->butterfly()->contiguousDouble().data() + startIndex, sizeof(JSValue) * static_cast<uint32_t>(count)); 755 764 else 756 gcSafeMemcpy(resultButterfly.contiguous().data(), butterfly()->contiguous().data() + startIndex, sizeof(JSValue) * count);765 gcSafeMemcpy(resultButterfly.contiguous().data(), source->butterfly()->contiguous().data() + startIndex, sizeof(JSValue) * static_cast<uint32_t>(count)); 757 766 758 767 ASSERT(resultButterfly.publicLength() == count); -
trunk/Source/JavaScriptCore/runtime/JSArray.h
r286572 r287800 105 105 JS_EXPORT_PRIVATE JSValue pop(JSGlobalObject*); 106 106 107 JSArray* fastSlice(JSGlobalObject*, unsigned startIndex, unsignedcount);107 static JSArray* fastSlice(JSGlobalObject*, JSObject* source, uint64_t startIndex, uint64_t count); 108 108 109 109 bool canFastCopy(VM&, JSArray* otherArray);
Note:
See TracChangeset
for help on using the changeset viewer.