Diff
Modified: trunk/JSTests/ChangeLog (259028 => 259029)
--- trunk/JSTests/ChangeLog 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/JSTests/ChangeLog 2020-03-26 02:24:29 UTC (rev 259029)
@@ -1,5 +1,14 @@
2020-03-25 Alexey Shvayka <shvaikal...@gmail.com>
+ RegExp.prototype[@@replace] relies on globals and doesn't perform ToLength
+ https://bugs.webkit.org/show_bug.cgi?id=173867
+
+ Reviewed by Ross Kirsling.
+
+ * test262/expectations.yaml: Mark 4 test cases as passing.
+
+2020-03-25 Alexey Shvayka <shvaikal...@gmail.com>
+
Invalid numeric and named references should be early syntax errors
https://bugs.webkit.org/show_bug.cgi?id=178175
Modified: trunk/JSTests/test262/expectations.yaml (259028 => 259029)
--- trunk/JSTests/test262/expectations.yaml 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/JSTests/test262/expectations.yaml 2020-03-26 02:24:29 UTC (rev 259029)
@@ -1654,12 +1654,6 @@
test/built-ins/RegExp/prototype/Symbol.match/builtin-infer-unicode.js:
default: 'Test262Error: Expected SameValue(«�», «null») to be true'
strict mode: 'Test262Error: Expected SameValue(«�», «null») to be true'
-test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js:
- default: 'Test262Error: Expected SameValue(«18014398509481984», «9007199254740992») to be true'
- strict mode: 'Test262Error: Expected SameValue(«18014398509481984», «9007199254740992») to be true'
-test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js:
- default: 'TypeError: undefined is not a function'
- strict mode: 'TypeError: undefined is not a function'
test/built-ins/RegExp/prototype/Symbol.search/set-lastindex-init-samevalue.js:
default: 'Test262Error: Expected SameValue(«0», «0») to be true'
strict mode: 'Test262Error: Expected SameValue(«0», «0») to be true'
Modified: trunk/Source/_javascript_Core/ChangeLog (259028 => 259029)
--- trunk/Source/_javascript_Core/ChangeLog 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-03-26 02:24:29 UTC (rev 259029)
@@ -1,5 +1,51 @@
2020-03-25 Alexey Shvayka <shvaikal...@gmail.com>
+ RegExp.prototype[@@replace] relies on globals and doesn't perform ToLength
+ https://bugs.webkit.org/show_bug.cgi?id=173867
+
+ Reviewed by Ross Kirsling.
+
+ This change:
+
+ a) Adds "lastIndex" ToLength coercion [1], which is observable, unlike ToLength coercion
+ of RegExpExec result [2] that we omit, just like the one in @@split [3].
+
+ b) Removes `lastPosition` checks/updates, as there are none in the spec, and it was
+ equivalent to checking `nextSourcePosition`.
+
+ c) Removes reliance of @@replace on globals and also replaces @stringSubstrInternal
+ built-in with @stringSubstringInternal, as the former is Annex B and accepts size
+ as 2nd paramter, which is not very handy because ECMA-262 usually says "substring
+ of S consisting of the code units at indices X (inclusive) through Y (exclusive)".
+
+ [1]: https://tc39.es/ecma262/#sec-regexp.prototype-@@replace (step 11.c.iii.2.a)
+ [2]: https://tc39.es/ecma262/#sec-regexp.prototype-@@replace (step 14.a)
+ [3]: https://tc39.es/ecma262/#sec-regexp.prototype-@@split (step 19.d.iv.6)
+
+ * builtins/BuiltinNames.h:
+ * builtins/RegExpPrototype.js:
+ (getSubstitution):
+ (Symbol.replace):
+ (Symbol.split):
+ * builtins/StringPrototype.js:
+ (globalPrivate.repeatCharactersSlowPath):
+ * bytecode/LinkTimeConstant.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ * runtime/StringPrototype.cpp:
+ (JSC::stringIndexOfImpl):
+ (JSC::stringProtoFuncIndexOf):
+ (JSC::builtinStringIndexOfInternal):
+ (JSC::stringProtoFuncSubstr):
+ (JSC::stringSubstringImpl):
+ (JSC::stringProtoFuncSubstring):
+ (JSC::builtinStringSubstringInternal):
+ (JSC::stringProtoFuncSubstrImpl): Deleted.
+ (JSC::builtinStringSubstrInternal): Deleted.
+ * runtime/StringPrototype.h:
+
+2020-03-25 Alexey Shvayka <shvaikal...@gmail.com>
+
Invalid numeric and named references should be early syntax errors
https://bugs.webkit.org/show_bug.cgi?id=178175
Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (259028 => 259029)
--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2020-03-26 02:24:29 UTC (rev 259029)
@@ -159,8 +159,9 @@
macro(regExpStringIteratorUnicode) \
macro(regExpStringIteratorDone) \
macro(stringIncludesInternal) \
+ macro(stringIndexOfInternal) \
macro(stringSplitFast) \
- macro(stringSubstrInternal) \
+ macro(stringSubstringInternal) \
macro(makeBoundFunction) \
macro(hasOwnLengthProperty) \
macro(importModule) \
Modified: trunk/Source/_javascript_Core/builtins/RegExpPrototype.js (259028 => 259029)
--- trunk/Source/_javascript_Core/builtins/RegExpPrototype.js 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/builtins/RegExpPrototype.js 2020-03-26 02:24:29 UTC (rev 259029)
@@ -191,14 +191,14 @@
var result = "";
var lastStart = 0;
- for (var start = 0; start = replacement.indexOf("$", lastStart), start !== -1; lastStart = start) {
+ for (var start = 0; start = @stringIndexOfInternal.@call(replacement, "$", lastStart), start !== -1; lastStart = start) {
if (start - lastStart > 0)
- result = result + replacement.substring(lastStart, start);
+ result = result + @stringSubstringInternal.@call(replacement, lastStart, start);
start++;
- var ch = replacement.charAt(start);
- if (ch === "")
+ if (start >= replacementLength)
result = result + "$";
else {
+ var ch = replacement[start];
switch (ch)
{
case "$":
@@ -211,20 +211,20 @@
break;
case "`":
if (position > 0)
- result = result + str.substring(0, position);
+ result = result + @stringSubstringInternal.@call(str, 0, position);
start++;
break;
case "'":
if (tailPos < stringLength)
- result = result + str.substring(tailPos);
+ result = result + @stringSubstringInternal.@call(str, tailPos);
start++;
break;
case "<":
if (namedCaptures !== @undefined) {
var groupNameStartIndex = start + 1;
- var groupNameEndIndex = replacement.indexOf(">", groupNameStartIndex);
+ var groupNameEndIndex = @stringIndexOfInternal.@call(replacement, ">", groupNameStartIndex);
if (groupNameEndIndex !== -1) {
- var groupName = replacement.substring(groupNameStartIndex, groupNameEndIndex);
+ var groupName = @stringSubstringInternal.@call(replacement, groupNameStartIndex, groupNameEndIndex);
var capture = namedCaptures[groupName];
if (capture !== @undefined)
result = result + @toString(capture);
@@ -238,7 +238,7 @@
start++;
break;
default:
- var chCode = ch.charCodeAt(0);
+ var chCode = ch.@charCodeAt(0);
if (chCode >= 0x30 && chCode <= 0x39) {
var originalStart = start - 1;
start++;
@@ -245,12 +245,12 @@
var n = chCode - 0x30;
if (n > m) {
- result = result + replacement.substring(originalStart, start);
+ result = result + @stringSubstringInternal.@call(replacement, originalStart, start);
break;
}
if (start < replacementLength) {
- var nextChCode = replacement.charCodeAt(start);
+ var nextChCode = replacement.@charCodeAt(start);
if (nextChCode >= 0x30 && nextChCode <= 0x39) {
var nn = 10 * n + nextChCode - 0x30;
if (nn <= m) {
@@ -261,7 +261,7 @@
}
if (n == 0) {
- result = result + replacement.substring(originalStart, start);
+ result = result + @stringSubstringInternal.@call(replacement, originalStart, start);
break;
}
@@ -275,7 +275,7 @@
}
}
- return result + replacement.substring(lastStart);
+ return result + @stringSubstringInternal.@call(replacement, lastStart);
}
if (!@isObject(this))
@@ -313,8 +313,10 @@
else {
var matchStr = @toString(result[0]);
- if (!matchStr.length)
- regexp.lastIndex = @advanceStringIndex(str, regexp.lastIndex, unicode);
+ if (!matchStr.length) {
+ var thisIndex = @toLength(regexp.lastIndex);
+ regexp.lastIndex = @advanceStringIndex(str, thisIndex, unicode);
+ }
}
}
}
@@ -321,7 +323,6 @@
var accumulatedResult = "";
var nextSourcePosition = 0;
- var lastPosition = 0;
for (var i = 0, resultListLength = resultList.length; i < resultListLength; ++i) {
var result = resultList[i];
@@ -346,7 +347,10 @@
var namedCaptures = result.groups;
if (functionalReplace) {
- var replacerArgs = [ matched ].concat(captures);
+ var replacerArgs = [ matched ];
+ for (var j = 0; j < captures.length; j++)
+ replacerArgs.@push(captures[j]);
+
replacerArgs.@push(position);
replacerArgs.@push(str);
@@ -362,10 +366,9 @@
replacement = getSubstitution(matched, str, position, captures, namedCaptures, replace);
}
- if (position >= nextSourcePosition && position >= lastPosition) {
- accumulatedResult = accumulatedResult + str.substring(nextSourcePosition, position) + replacement;
+ if (position >= nextSourcePosition) {
+ accumulatedResult = accumulatedResult + @stringSubstringInternal.@call(str, nextSourcePosition, position) + replacement;
nextSourcePosition = position + matchLength;
- lastPosition = position;
}
}
@@ -372,7 +375,7 @@
if (nextSourcePosition >= stringLength)
return accumulatedResult;
- return accumulatedResult + str.substring(nextSourcePosition);
+ return accumulatedResult + @stringSubstringInternal.@call(str, nextSourcePosition);
}
// 21.2.5.9 RegExp.prototype[@@search] (string)
@@ -562,7 +565,7 @@
// iv. Else e != p,
else {
// 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive).
- var subStr = @stringSubstrInternal.@call(str, position, matchPosition - position);
+ var subStr = @stringSubstringInternal.@call(str, position, matchPosition);
// 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
// 3. Let lengthA be lengthA + 1.
@putByValDirect(result, result.length, subStr);
@@ -597,7 +600,7 @@
}
}
// 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
- var remainingStr = @stringSubstrInternal.@call(str, position, size);
+ var remainingStr = @stringSubstringInternal.@call(str, position, size);
// 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
@putByValDirect(result, result.length, remainingStr);
// 22. Return A.
Modified: trunk/Source/_javascript_Core/builtins/StringPrototype.js (259028 => 259029)
--- trunk/Source/_javascript_Core/builtins/StringPrototype.js 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/builtins/StringPrototype.js 2020-03-26 02:24:29 UTC (rev 259029)
@@ -113,7 +113,7 @@
operand += operand;
}
if (remainingCharacters)
- result += @stringSubstrInternal.@call(string, 0, remainingCharacters);
+ result += @stringSubstringInternal.@call(string, 0, remainingCharacters);
return result;
}
Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (259028 => 259029)
--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2020-03-26 02:24:29 UTC (rev 259029)
@@ -90,8 +90,9 @@
v(regExpPrototypeSymbolReplace, nullptr) \
v(regExpTestFast, nullptr) \
v(stringIncludesInternal, nullptr) \
+ v(stringIndexOfInternal, nullptr) \
v(stringSplitFast, nullptr) \
- v(stringSubstrInternal, nullptr) \
+ v(stringSubstringInternal, nullptr) \
v(makeBoundFunction, nullptr) \
v(hasOwnLengthProperty, nullptr) \
v(dateTimeFormat, nullptr) \
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (259028 => 259029)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-03-26 02:24:29 UTC (rev 259029)
@@ -1142,11 +1142,14 @@
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringIncludesInternal)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 1, String(), builtinStringIncludesInternal));
});
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringIndexOfInternal)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 1, String(), builtinStringIndexOfInternal));
+ });
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSplitFast)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), stringProtoFuncSplitFast));
});
- m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSubstrInternal)].initLater([] (const Initializer<JSCell>& init) {
- init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), builtinStringSubstrInternal));
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::stringSubstringInternal)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), builtinStringSubstringInternal));
});
// Function prototype helpers.
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (259028 => 259029)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2020-03-26 02:24:29 UTC (rev 259029)
@@ -1076,7 +1076,7 @@
return JSValue::encode(jsUndefined());
}
-EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)
+static EncodedJSValue stringIndexOfImpl(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1123,6 +1123,19 @@
return JSValue::encode(jsNumber(result));
}
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ return stringIndexOfImpl(globalObject, callFrame);
+}
+
+EncodedJSValue JSC_HOST_CALL builtinStringIndexOfInternal(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ ASSERT(callFrame->thisValue().isString());
+ ASSERT(callFrame->argument(0).isString());
+ ASSERT(callFrame->argument(1).isNumber() || callFrame->argument(1).isUndefined());
+ return stringIndexOfImpl(globalObject, callFrame);
+}
+
EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = globalObject->vm();
@@ -1365,7 +1378,7 @@
return JSValue::encode(result);
}
-static EncodedJSValue stringProtoFuncSubstrImpl(JSGlobalObject* globalObject, CallFrame* callFrame)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1409,27 +1422,8 @@
return JSValue::encode(jsSubstring(vm, uString, substringStart, substringLength));
}
-EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(JSGlobalObject* globalObject, CallFrame* callFrame)
+static EncodedJSValue stringSubstringImpl(JSGlobalObject* globalObject, CallFrame* callFrame)
{
- return stringProtoFuncSubstrImpl(globalObject, callFrame);
-}
-
-EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(JSGlobalObject* globalObject, CallFrame* callFrame)
-{
- // @substrInternal should not have any observable side effects (e.g. it should not call
- // GetMethod(..., @@toPrimitive) on the thisValue).
-
- // It is ok to use the default stringProtoFuncSubstr as the implementation of
- // @substrInternal because @substrInternal will only be called by builtins, which will
- // guarantee that we only pass it a string thisValue. As a result, stringProtoFuncSubstr
- // will not need to call toString() on the thisValue, and there will be no observable
- // side-effects.
- ASSERT(callFrame->thisValue().isString());
- return stringProtoFuncSubstrImpl(globalObject, callFrame);
-}
-
-EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(JSGlobalObject* globalObject, CallFrame* callFrame)
-{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1472,6 +1466,19 @@
RELEASE_AND_RETURN(scope, JSValue::encode(jsSubstring(globalObject, jsString, substringStart, substringLength)));
}
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ return stringSubstringImpl(globalObject, callFrame);
+}
+
+EncodedJSValue JSC_HOST_CALL builtinStringSubstringInternal(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ ASSERT(callFrame->thisValue().isString());
+ ASSERT(callFrame->argument(0).isNumber());
+ ASSERT(callFrame->argument(1).isNumber() || callFrame->argument(1).isUndefined());
+ return stringSubstringImpl(globalObject, callFrame);
+}
+
EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.h (259028 => 259029)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.h 2020-03-26 02:10:38 UTC (rev 259028)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.h 2020-03-26 02:24:29 UTC (rev 259029)
@@ -60,7 +60,8 @@
EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeatCharacter(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncSplitFast(JSGlobalObject*, CallFrame*);
-EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(JSGlobalObject*, CallFrame*);
+EncodedJSValue JSC_HOST_CALL builtinStringSubstringInternal(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL builtinStringIncludesInternal(JSGlobalObject*, CallFrame*);
+EncodedJSValue JSC_HOST_CALL builtinStringIndexOfInternal(JSGlobalObject*, CallFrame*);
} // namespace JSC