Changeset 259029 in webkit
- Timestamp:
- Mar 25, 2020 7:24:29 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r259026 r259029 1 2020-03-25 Alexey Shvayka <shvaikalesh@gmail.com> 2 3 RegExp.prototype[@@replace] relies on globals and doesn't perform ToLength 4 https://bugs.webkit.org/show_bug.cgi?id=173867 5 6 Reviewed by Ross Kirsling. 7 8 * test262/expectations.yaml: Mark 4 test cases as passing. 9 1 10 2020-03-25 Alexey Shvayka <shvaikalesh@gmail.com> 2 11 -
trunk/JSTests/test262/expectations.yaml
r259026 r259029 1655 1655 default: 'Test262Error: Expected SameValue(«�», «null») to be true' 1656 1656 strict mode: 'Test262Error: Expected SameValue(«�», «null») to be true' 1657 test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js:1658 default: 'Test262Error: Expected SameValue(«18014398509481984», «9007199254740992») to be true'1659 strict mode: 'Test262Error: Expected SameValue(«18014398509481984», «9007199254740992») to be true'1660 test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js:1661 default: 'TypeError: undefined is not a function'1662 strict mode: 'TypeError: undefined is not a function'1663 1657 test/built-ins/RegExp/prototype/Symbol.search/set-lastindex-init-samevalue.js: 1664 1658 default: 'Test262Error: Expected SameValue(«0», «0») to be true' -
trunk/Source/JavaScriptCore/ChangeLog
r259026 r259029 1 2020-03-25 Alexey Shvayka <shvaikalesh@gmail.com> 2 3 RegExp.prototype[@@replace] relies on globals and doesn't perform ToLength 4 https://bugs.webkit.org/show_bug.cgi?id=173867 5 6 Reviewed by Ross Kirsling. 7 8 This change: 9 10 a) Adds "lastIndex" ToLength coercion [1], which is observable, unlike ToLength coercion 11 of RegExpExec result [2] that we omit, just like the one in @@split [3]. 12 13 b) Removes `lastPosition` checks/updates, as there are none in the spec, and it was 14 equivalent to checking `nextSourcePosition`. 15 16 c) Removes reliance of @@replace on globals and also replaces @stringSubstrInternal 17 built-in with @stringSubstringInternal, as the former is Annex B and accepts size 18 as 2nd paramter, which is not very handy because ECMA-262 usually says "substring 19 of S consisting of the code units at indices X (inclusive) through Y (exclusive)". 20 21 [1]: https://tc39.es/ecma262/#sec-regexp.prototype-@@replace (step 11.c.iii.2.a) 22 [2]: https://tc39.es/ecma262/#sec-regexp.prototype-@@replace (step 14.a) 23 [3]: https://tc39.es/ecma262/#sec-regexp.prototype-@@split (step 19.d.iv.6) 24 25 * builtins/BuiltinNames.h: 26 * builtins/RegExpPrototype.js: 27 (getSubstitution): 28 (Symbol.replace): 29 (Symbol.split): 30 * builtins/StringPrototype.js: 31 (globalPrivate.repeatCharactersSlowPath): 32 * bytecode/LinkTimeConstant.h: 33 * runtime/JSGlobalObject.cpp: 34 (JSC::JSGlobalObject::init): 35 * runtime/StringPrototype.cpp: 36 (JSC::stringIndexOfImpl): 37 (JSC::stringProtoFuncIndexOf): 38 (JSC::builtinStringIndexOfInternal): 39 (JSC::stringProtoFuncSubstr): 40 (JSC::stringSubstringImpl): 41 (JSC::stringProtoFuncSubstring): 42 (JSC::builtinStringSubstringInternal): 43 (JSC::stringProtoFuncSubstrImpl): Deleted. 44 (JSC::builtinStringSubstrInternal): Deleted. 45 * runtime/StringPrototype.h: 46 1 47 2020-03-25 Alexey Shvayka <shvaikalesh@gmail.com> 2 48 -
trunk/Source/JavaScriptCore/builtins/BuiltinNames.h
r258801 r259029 160 160 macro(regExpStringIteratorDone) \ 161 161 macro(stringIncludesInternal) \ 162 macro(stringIndexOfInternal) \ 162 163 macro(stringSplitFast) \ 163 macro(stringSubstr Internal) \164 macro(stringSubstringInternal) \ 164 165 macro(makeBoundFunction) \ 165 166 macro(hasOwnLengthProperty) \ -
trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js
r258968 r259029 192 192 var lastStart = 0; 193 193 194 for (var start = 0; start = replacement.indexOf("$", lastStart), start !== -1; lastStart = start) {194 for (var start = 0; start = @stringIndexOfInternal.@call(replacement, "$", lastStart), start !== -1; lastStart = start) { 195 195 if (start - lastStart > 0) 196 result = result + replacement.substring(lastStart, start);196 result = result + @stringSubstringInternal.@call(replacement, lastStart, start); 197 197 start++; 198 var ch = replacement.charAt(start); 199 if (ch === "") 198 if (start >= replacementLength) 200 199 result = result + "$"; 201 200 else { 201 var ch = replacement[start]; 202 202 switch (ch) 203 203 { … … 212 212 case "`": 213 213 if (position > 0) 214 result = result + str.substring(0, position);214 result = result + @stringSubstringInternal.@call(str, 0, position); 215 215 start++; 216 216 break; 217 217 case "'": 218 218 if (tailPos < stringLength) 219 result = result + str.substring(tailPos);219 result = result + @stringSubstringInternal.@call(str, tailPos); 220 220 start++; 221 221 break; … … 223 223 if (namedCaptures !== @undefined) { 224 224 var groupNameStartIndex = start + 1; 225 var groupNameEndIndex = replacement.indexOf(">", groupNameStartIndex);225 var groupNameEndIndex = @stringIndexOfInternal.@call(replacement, ">", groupNameStartIndex); 226 226 if (groupNameEndIndex !== -1) { 227 var groupName = replacement.substring(groupNameStartIndex, groupNameEndIndex);227 var groupName = @stringSubstringInternal.@call(replacement, groupNameStartIndex, groupNameEndIndex); 228 228 var capture = namedCaptures[groupName]; 229 229 if (capture !== @undefined) … … 239 239 break; 240 240 default: 241 var chCode = ch. charCodeAt(0);241 var chCode = ch.@charCodeAt(0); 242 242 if (chCode >= 0x30 && chCode <= 0x39) { 243 243 var originalStart = start - 1; … … 246 246 var n = chCode - 0x30; 247 247 if (n > m) { 248 result = result + replacement.substring(originalStart, start);248 result = result + @stringSubstringInternal.@call(replacement, originalStart, start); 249 249 break; 250 250 } 251 251 252 252 if (start < replacementLength) { 253 var nextChCode = replacement. charCodeAt(start);253 var nextChCode = replacement.@charCodeAt(start); 254 254 if (nextChCode >= 0x30 && nextChCode <= 0x39) { 255 255 var nn = 10 * n + nextChCode - 0x30; … … 262 262 263 263 if (n == 0) { 264 result = result + replacement.substring(originalStart, start);264 result = result + @stringSubstringInternal.@call(replacement, originalStart, start); 265 265 break; 266 266 } … … 276 276 } 277 277 278 return result + replacement.substring(lastStart);278 return result + @stringSubstringInternal.@call(replacement, lastStart); 279 279 } 280 280 … … 314 314 var matchStr = @toString(result[0]); 315 315 316 if (!matchStr.length) 317 regexp.lastIndex = @advanceStringIndex(str, regexp.lastIndex, unicode); 316 if (!matchStr.length) { 317 var thisIndex = @toLength(regexp.lastIndex); 318 regexp.lastIndex = @advanceStringIndex(str, thisIndex, unicode); 319 } 318 320 } 319 321 } … … 322 324 var accumulatedResult = ""; 323 325 var nextSourcePosition = 0; 324 var lastPosition = 0;325 326 326 327 for (var i = 0, resultListLength = resultList.length; i < resultListLength; ++i) { … … 347 348 348 349 if (functionalReplace) { 349 var replacerArgs = [ matched ].concat(captures); 350 var replacerArgs = [ matched ]; 351 for (var j = 0; j < captures.length; j++) 352 replacerArgs.@push(captures[j]); 353 350 354 replacerArgs.@push(position); 351 355 replacerArgs.@push(str); … … 363 367 } 364 368 365 if (position >= nextSourcePosition && position >= lastPosition) {366 accumulatedResult = accumulatedResult + str.substring(nextSourcePosition, position) + replacement;369 if (position >= nextSourcePosition) { 370 accumulatedResult = accumulatedResult + @stringSubstringInternal.@call(str, nextSourcePosition, position) + replacement; 367 371 nextSourcePosition = position + matchLength; 368 lastPosition = position;369 372 } 370 373 } … … 373 376 return accumulatedResult; 374 377 375 return accumulatedResult + str.substring(nextSourcePosition);378 return accumulatedResult + @stringSubstringInternal.@call(str, nextSourcePosition); 376 379 } 377 380 … … 563 566 else { 564 567 // 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive). 565 var subStr = @stringSubstr Internal.@call(str, position, matchPosition - position);568 var subStr = @stringSubstringInternal.@call(str, position, matchPosition); 566 569 // 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T). 567 570 // 3. Let lengthA be lengthA + 1. … … 598 601 } 599 602 // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive). 600 var remainingStr = @stringSubstr Internal.@call(str, position, size);603 var remainingStr = @stringSubstringInternal.@call(str, position, size); 601 604 // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T). 602 605 @putByValDirect(result, result.length, remainingStr); -
trunk/Source/JavaScriptCore/builtins/StringPrototype.js
r257681 r259029 114 114 } 115 115 if (remainingCharacters) 116 result += @stringSubstr Internal.@call(string, 0, remainingCharacters);116 result += @stringSubstringInternal.@call(string, 0, remainingCharacters); 117 117 return result; 118 118 } -
trunk/Source/JavaScriptCore/bytecode/LinkTimeConstant.h
r258801 r259029 91 91 v(regExpTestFast, nullptr) \ 92 92 v(stringIncludesInternal, nullptr) \ 93 v(stringIndexOfInternal, nullptr) \ 93 94 v(stringSplitFast, nullptr) \ 94 v(stringSubstr Internal, nullptr) \95 v(stringSubstringInternal, nullptr) \ 95 96 v(makeBoundFunction, nullptr) \ 96 97 v(hasOwnLengthProperty, nullptr) \ -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r258801 r259029 1143 1143 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 1, String(), builtinStringIncludesInternal)); 1144 1144 }); 1145 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringIndexOfInternal)].initLater([] (const Initializer<JSCell>& init) { 1146 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 1, String(), builtinStringIndexOfInternal)); 1147 }); 1145 1148 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSplitFast)].initLater([] (const Initializer<JSCell>& init) { 1146 1149 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), stringProtoFuncSplitFast)); 1147 1150 }); 1148 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSubstr Internal)].initLater([] (const Initializer<JSCell>& init) {1149 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), builtinStringSubstr Internal));1151 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSubstringInternal)].initLater([] (const Initializer<JSCell>& init) { 1152 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), builtinStringSubstringInternal)); 1150 1153 }); 1151 1154 -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r258443 r259029 1077 1077 } 1078 1078 1079 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)1079 static EncodedJSValue stringIndexOfImpl(JSGlobalObject* globalObject, CallFrame* callFrame) 1080 1080 { 1081 1081 VM& vm = globalObject->vm(); … … 1122 1122 return JSValue::encode(jsNumber(-1)); 1123 1123 return JSValue::encode(jsNumber(result)); 1124 } 1125 1126 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame) 1127 { 1128 return stringIndexOfImpl(globalObject, callFrame); 1129 } 1130 1131 EncodedJSValue JSC_HOST_CALL builtinStringIndexOfInternal(JSGlobalObject* globalObject, CallFrame* callFrame) 1132 { 1133 ASSERT(callFrame->thisValue().isString()); 1134 ASSERT(callFrame->argument(0).isString()); 1135 ASSERT(callFrame->argument(1).isNumber() || callFrame->argument(1).isUndefined()); 1136 return stringIndexOfImpl(globalObject, callFrame); 1124 1137 } 1125 1138 … … 1366 1379 } 1367 1380 1368 static EncodedJSValue stringProtoFuncSubstrImpl(JSGlobalObject* globalObject, CallFrame* callFrame)1381 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(JSGlobalObject* globalObject, CallFrame* callFrame) 1369 1382 { 1370 1383 VM& vm = globalObject->vm(); … … 1410 1423 } 1411 1424 1412 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(JSGlobalObject* globalObject, CallFrame* callFrame) 1413 { 1414 return stringProtoFuncSubstrImpl(globalObject, callFrame); 1415 } 1416 1417 EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(JSGlobalObject* globalObject, CallFrame* callFrame) 1418 { 1419 // @substrInternal should not have any observable side effects (e.g. it should not call 1420 // GetMethod(..., @@toPrimitive) on the thisValue). 1421 1422 // It is ok to use the default stringProtoFuncSubstr as the implementation of 1423 // @substrInternal because @substrInternal will only be called by builtins, which will 1424 // guarantee that we only pass it a string thisValue. As a result, stringProtoFuncSubstr 1425 // will not need to call toString() on the thisValue, and there will be no observable 1426 // side-effects. 1427 ASSERT(callFrame->thisValue().isString()); 1428 return stringProtoFuncSubstrImpl(globalObject, callFrame); 1429 } 1430 1431 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(JSGlobalObject* globalObject, CallFrame* callFrame) 1425 static EncodedJSValue stringSubstringImpl(JSGlobalObject* globalObject, CallFrame* callFrame) 1432 1426 { 1433 1427 VM& vm = globalObject->vm(); … … 1471 1465 unsigned substringLength = static_cast<unsigned>(end) - substringStart; 1472 1466 RELEASE_AND_RETURN(scope, JSValue::encode(jsSubstring(globalObject, jsString, substringStart, substringLength))); 1467 } 1468 1469 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(JSGlobalObject* globalObject, CallFrame* callFrame) 1470 { 1471 return stringSubstringImpl(globalObject, callFrame); 1472 } 1473 1474 EncodedJSValue JSC_HOST_CALL builtinStringSubstringInternal(JSGlobalObject* globalObject, CallFrame* callFrame) 1475 { 1476 ASSERT(callFrame->thisValue().isString()); 1477 ASSERT(callFrame->argument(0).isNumber()); 1478 ASSERT(callFrame->argument(1).isNumber() || callFrame->argument(1).isUndefined()); 1479 return stringSubstringImpl(globalObject, callFrame); 1473 1480 } 1474 1481 -
trunk/Source/JavaScriptCore/runtime/StringPrototype.h
r253432 r259029 61 61 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplitFast(JSGlobalObject*, CallFrame*); 62 62 63 EncodedJSValue JSC_HOST_CALL builtinStringSubstr Internal(JSGlobalObject*, CallFrame*);63 EncodedJSValue JSC_HOST_CALL builtinStringSubstringInternal(JSGlobalObject*, CallFrame*); 64 64 EncodedJSValue JSC_HOST_CALL builtinStringIncludesInternal(JSGlobalObject*, CallFrame*); 65 EncodedJSValue JSC_HOST_CALL builtinStringIndexOfInternal(JSGlobalObject*, CallFrame*); 65 66 66 67 } // namespace JSC
Note: See TracChangeset
for help on using the changeset viewer.