Changeset 236240 in webkit
- Timestamp:
- Sep 19, 2018, 10:54:27 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 7 added
- 9 edited
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/stress/array-indexof-array-prototype-trap.js (added)
-
JSTests/stress/array-indexof-have-a-bad-time-c-runtime.js (added)
-
JSTests/stress/array-indexof-hole-nan.js (added)
-
JSTests/stress/array-indexof-infinity.js (added)
-
JSTests/stress/array-indexof-negative-zero.js (added)
-
JSTests/stress/array-indexof-own-getter.js (added)
-
JSTests/stress/array-indexof-prototype-trap.js (added)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/runtime/ArrayPrototype.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSArray.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSArrayInlines.h (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/JSCJSValueInlines.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSGlobalObject.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/MathCommon.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r236223 r236240 1 2018-09-19 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 3 [JSC] Optimize Array#indexOf in C++ runtime 4 https://bugs.webkit.org/show_bug.cgi?id=189507 5 6 Reviewed by Saam Barati. 7 8 * stress/array-indexof-array-prototype-trap.js: Added. 9 (shouldBe): 10 (AncestorArray.prototype.get 2): 11 (AncestorArray): 12 * stress/array-indexof-have-a-bad-time-c-runtime.js: Added. 13 (shouldBe): 14 * stress/array-indexof-hole-nan.js: Added. 15 (shouldBe): 16 (throw.new.Error): 17 * stress/array-indexof-infinity.js: Added. 18 (shouldBe): 19 (throw.new.Error): 20 * stress/array-indexof-negative-zero.js: Added. 21 (shouldBe): 22 (throw.new.Error): 23 * stress/array-indexof-own-getter.js: Added. 24 (shouldBe): 25 (throw.new.Error.get array): 26 (get array): 27 * stress/array-indexof-prototype-trap.js: Added. 28 (shouldBe): 29 (DerivedArray.prototype.get 2): 30 (DerivedArray): 31 1 32 2018-09-19 Saam barati <sbarati@apple.com> 2 33 -
trunk/Source/JavaScriptCore/ChangeLog
r236235 r236240 1 2018-09-19 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 3 [JSC] Optimize Array#indexOf in C++ runtime 4 https://bugs.webkit.org/show_bug.cgi?id=189507 5 6 Reviewed by Saam Barati. 7 8 C++ Array#indexOf runtime function takes so much time in babylon benchmark in 9 web-tooling-benchmark. While our DFG and FTL has Array#indexOf optimization 10 and actually it is working well, C++ Array#indexOf is called significant amount 11 of time before tiering up, and it takes 6.74% of jsc main thread samples according 12 to perf command in Linux. This is because C++ Array#indexOf is too generic and 13 misses the chance to optimize JSArray cases. 14 15 This patch adds JSArray fast path for Array#indexOf. If we know that indexed 16 access to the given JSArray is non-observable and indexing type is good for the fast 17 path, we go to the fast path. This makes sampling of Array#indexOf 3.83% in 18 babylon web-tooling-benchmark. 19 20 * runtime/ArrayPrototype.cpp: 21 (JSC::arrayProtoFuncIndexOf): 22 * runtime/JSArray.h: 23 * runtime/JSArrayInlines.h: 24 (JSC::JSArray::canDoFastIndexedAccess): 25 (JSC::toLength): 26 * runtime/JSCJSValueInlines.h: 27 (JSC::JSValue::JSValue): 28 * runtime/JSGlobalObject.h: 29 * runtime/JSGlobalObjectInlines.h: 30 (JSC::JSGlobalObject::isArrayPrototypeIndexedAccessFastAndNonObservable): 31 (JSC::JSGlobalObject::isArrayPrototypeIteratorProtocolFastAndNonObservable): 32 * runtime/MathCommon.h: 33 (JSC::canBeStrictInt32): 34 (JSC::canBeInt32): 35 1 36 2018-09-19 Michael Saboff <msaboff@apple.com> 2 37 -
trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
r235540 r236240 1157 1157 1158 1158 // 15.4.4.14 1159 JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);1160 EXCEPTION_ASSERT(!!scope.exception() == !thisObj );1161 if (UNLIKELY(!thisObj ))1162 return encodedJSValue();1163 unsigned length = toLength(exec, thisObj );1164 RETURN_IF_EXCEPTION(scope, encodedJSValue());1159 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 1160 EXCEPTION_ASSERT(!!scope.exception() == !thisObject); 1161 if (UNLIKELY(!thisObject)) 1162 return { }; 1163 unsigned length = toLength(exec, thisObject); 1164 RETURN_IF_EXCEPTION(scope, { }); 1165 1165 1166 1166 unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); 1167 RETURN_IF_EXCEPTION(scope, encodedJSValue());1167 RETURN_IF_EXCEPTION(scope, { }); 1168 1168 JSValue searchElement = exec->argument(0); 1169 1170 if (isJSArray(thisObject)) { 1171 JSArray* array = asArray(thisObject); 1172 if (array->canDoFastIndexedAccess(vm)) { 1173 switch (array->indexingType()) { 1174 case ALL_INT32_INDEXING_TYPES: { 1175 if (!searchElement.isNumber()) 1176 return JSValue::encode(jsNumber(-1)); 1177 JSValue searchInt32; 1178 if (searchElement.isInt32()) 1179 searchInt32 = searchElement; 1180 else { 1181 double searchNumber = searchElement.asNumber(); 1182 if (!canBeInt32(searchNumber)) 1183 return JSValue::encode(jsNumber(-1)); 1184 searchInt32 = jsNumber(static_cast<int32_t>(searchNumber)); 1185 } 1186 auto& butterfly = *array->butterfly(); 1187 auto data = butterfly.contiguous().data(); 1188 for (; index < length; ++index) { 1189 // Array#indexOf uses `===` semantics (not HashMap isEqual semantics). 1190 // And the hole never matches against Int32 value. 1191 if (searchInt32 == data[index].get()) 1192 return JSValue::encode(jsNumber(index)); 1193 } 1194 return JSValue::encode(jsNumber(-1)); 1195 } 1196 case ALL_CONTIGUOUS_INDEXING_TYPES: { 1197 auto& butterfly = *array->butterfly(); 1198 auto data = butterfly.contiguous().data(); 1199 for (; index < length; ++index) { 1200 JSValue value = data[index].get(); 1201 if (!value) 1202 continue; 1203 bool isEqual = JSValue::strictEqual(exec, searchElement, value); 1204 RETURN_IF_EXCEPTION(scope, { }); 1205 if (isEqual) 1206 return JSValue::encode(jsNumber(index)); 1207 } 1208 return JSValue::encode(jsNumber(-1)); 1209 } 1210 case ALL_DOUBLE_INDEXING_TYPES: { 1211 if (!searchElement.isNumber()) 1212 return JSValue::encode(jsNumber(-1)); 1213 double searchNumber = searchElement.asNumber(); 1214 auto& butterfly = *array->butterfly(); 1215 auto data = butterfly.contiguousDouble().data(); 1216 for (; index < length; ++index) { 1217 // Array#indexOf uses `===` semantics (not HashMap isEqual semantics). 1218 // And the hole never matches since it is NaN. 1219 if (data[index] == searchNumber) 1220 return JSValue::encode(jsNumber(index)); 1221 } 1222 return JSValue::encode(jsNumber(-1)); 1223 } 1224 default: 1225 break; 1226 } 1227 } 1228 } 1229 1169 1230 for (; index < length; ++index) { 1170 JSValue e = getProperty(exec, thisObj , index);1171 RETURN_IF_EXCEPTION(scope, encodedJSValue());1231 JSValue e = getProperty(exec, thisObject, index); 1232 RETURN_IF_EXCEPTION(scope, { }); 1172 1233 if (!e) 1173 1234 continue; 1174 1235 bool isEqual = JSValue::strictEqual(exec, searchElement, e); 1175 RETURN_IF_EXCEPTION(scope, encodedJSValue());1236 RETURN_IF_EXCEPTION(scope, { }); 1176 1237 if (isEqual) 1177 1238 return JSValue::encode(jsNumber(index)); -
trunk/Source/JavaScriptCore/runtime/JSArray.h
r233722 r236240 102 102 103 103 bool canFastCopy(VM&, JSArray* otherArray); 104 bool canDoFastIndexedAccess(VM&); 104 105 // This function returns NonArray if the indexing types are not compatable for copying. 105 106 IndexingType mergeIndexingTypeForCopying(IndexingType other); -
trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h
r235356 r236240 20 20 #pragma once 21 21 22 #include "ArrayPrototype.h" 22 23 #include "Error.h" 23 24 #include "JSArray.h" … … 71 72 } 72 73 74 inline bool JSArray::canDoFastIndexedAccess(VM& vm) 75 { 76 JSGlobalObject* globalObject = this->globalObject(); 77 if (!globalObject->isArrayPrototypeIndexedAccessFastAndNonObservable()) 78 return false; 79 80 Structure* structure = this->structure(vm); 81 // This is the fast case. Many arrays will be an original array. 82 if (globalObject->isOriginalArrayStructure(structure)) 83 return true; 84 85 if (structure->mayInterceptIndexedAccesses()) 86 return false; 87 88 if (getPrototypeDirect(vm) != globalObject->arrayPrototype()) 89 return false; 90 91 return true; 92 } 93 73 94 ALWAYS_INLINE double toLength(ExecState* exec, JSObject* obj) 74 95 { 75 96 VM& vm = exec->vm(); 76 97 auto scope = DECLARE_THROW_SCOPE(vm); 77 if ( isJSArray(obj))98 if (LIKELY(isJSArray(obj))) 78 99 return jsCast<JSArray*>(obj)->length(); 79 100 -
trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
r235491 r236240 168 168 inline JSValue::JSValue(double d) 169 169 { 170 // Note: while this behavior is undefined for NaN and inf, the subsequent statement will catch these cases. 171 const int32_t asInt32 = static_cast<int32_t>(d); 172 if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0 173 *this = JSValue(EncodeAsDouble, d); 170 if (canBeStrictInt32(d)) { 171 *this = JSValue(static_cast<int32_t>(d)); 174 172 return; 175 173 } 176 *this = JSValue( static_cast<int32_t>(d));174 *this = JSValue(EncodeAsDouble, d); 177 175 } 178 176 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h
r235419 r236240 477 477 PoisonedUniquePtr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_numberPrototypeToStringWatchpoint; 478 478 479 bool isArrayPrototypeIndexedAccessFastAndNonObservable(); 479 480 bool isArrayPrototypeIteratorProtocolFastAndNonObservable(); 480 481 bool isMapPrototypeIteratorProtocolFastAndNonObservable(); -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
r223746 r236240 53 53 } 54 54 55 ALWAYS_INLINE bool JSGlobalObject::isArrayPrototypeIndexedAccessFastAndNonObservable() 56 { 57 // We're fast if we don't have any indexed properties on the prototype. 58 return !isHavingABadTime() && arrayPrototypeChainIsSane(); 59 } 55 60 56 61 ALWAYS_INLINE bool JSGlobalObject::isArrayPrototypeIteratorProtocolFastAndNonObservable() … … 64 69 // executing concurrently. 65 70 66 return arrayIteratorProtocolWatchpoint().isStillValid() && !isHavingABadTime() && arrayPrototypeChainIsSane();71 return arrayIteratorProtocolWatchpoint().isStillValid() && isArrayPrototypeIndexedAccessFastAndNonObservable(); 67 72 } 68 73 -
trunk/Source/JavaScriptCore/runtime/MathCommon.h
r232244 r236240 179 179 } 180 180 181 ALWAYS_INLINE bool canBeStrictInt32(double value) 182 { 183 // Note: while this behavior is undefined for NaN and inf, the subsequent statement will catch these cases. 184 const int32_t asInt32 = static_cast<int32_t>(value); 185 return !(asInt32 != value || (!asInt32 && std::signbit(value))); // true for -0.0 186 } 187 188 ALWAYS_INLINE bool canBeInt32(double value) 189 { 190 // Note: Strictly speaking this is an undefined behavior. 191 return static_cast<int32_t>(value) == value; 192 } 193 181 194 extern "C" { 182 195 double JIT_OPERATION jsRound(double value) REFERENCED_FROM_ASM WTF_INTERNAL;
Note:
See TracChangeset
for help on using the changeset viewer.