Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/regexp-replace.tq')
-rw-r--r--deps/v8/src/builtins/regexp-replace.tq459
1 files changed, 226 insertions, 233 deletions
diff --git a/deps/v8/src/builtins/regexp-replace.tq b/deps/v8/src/builtins/regexp-replace.tq
index fc9d13cf3c6..c59a41b27f6 100644
--- a/deps/v8/src/builtins/regexp-replace.tq
+++ b/deps/v8/src/builtins/regexp-replace.tq
@@ -6,259 +6,252 @@
namespace regexp {
- extern builtin
- SubString(implicit context: Context)(String, Smi, Smi): String;
-
- extern runtime RegExpExecMultiple(implicit context: Context)(
- JSRegExp, String, RegExpMatchInfo, JSArray): Null|JSArray;
- extern transitioning runtime
- RegExpReplaceRT(Context, JSReceiver, String, Object): String;
- extern transitioning runtime
- StringBuilderConcat(implicit context: Context)(JSArray, Smi, String): String;
- extern transitioning runtime
- StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)(
- String, JSRegExp, Callable): String;
-
- transitioning macro RegExpReplaceCallableNoExplicitCaptures(implicit context:
- Context)(
- matchesElements: FixedArray, matchesLength: intptr, string: String,
- replaceFn: Callable) {
- let matchStart: Smi = 0;
- for (let i: intptr = 0; i < matchesLength; i++) {
- typeswitch (matchesElements.objects[i]) {
- // Element represents a slice.
- case (elSmi: Smi): {
- // The slice's match start and end is either encoded as one or two
- // smis. A positive smi indicates a single smi encoding (see
- // ReplacementStringBuilder::AddSubjectSlice()).
- if (elSmi > 0) {
- // For single smi encoding, see
- // StringBuilderSubstringLength::encode() and
- // StringBuilderSubstringPosition::encode().
- const elInt: intptr = Convert<intptr>(elSmi);
- const newMatchStart: intptr = (elInt >> 11) + (elInt & 0x7FF);
- matchStart = Convert<Smi>(newMatchStart);
- } else {
- // For two smi encoding, the length is negative followed by the
- // match start.
- const nextEl: Smi = UnsafeCast<Smi>(matchesElements.objects[++i]);
- matchStart = nextEl - elSmi;
- }
- }
- // Element represents the matched substring, which is then passed to the
- // replace function.
- case (elString: String): {
- const replacementObj: JSAny =
- Call(context, replaceFn, Undefined, elString, matchStart, string);
- const replacement: String = ToString_Inline(replacementObj);
- matchesElements.objects[i] = replacement;
- matchStart += elString.length_smi;
- }
- case (Object): deferred {
- unreachable;
+extern builtin
+SubString(implicit context: Context)(String, Smi, Smi): String;
+
+extern runtime RegExpExecMultiple(implicit context: Context)(
+ JSRegExp, String, RegExpMatchInfo, JSArray): Null|JSArray;
+extern transitioning runtime
+RegExpReplaceRT(Context, JSReceiver, String, Object): String;
+extern transitioning runtime
+StringBuilderConcat(implicit context: Context)(JSArray, Smi, String): String;
+extern transitioning runtime
+StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)(
+ String, JSRegExp, Callable): String;
+
+transitioning macro RegExpReplaceCallableNoExplicitCaptures(
+ implicit context: Context)(
+ matchesElements: FixedArray, matchesLength: intptr, string: String,
+ replaceFn: Callable) {
+ let matchStart: Smi = 0;
+ for (let i: intptr = 0; i < matchesLength; i++) {
+ typeswitch (matchesElements.objects[i]) {
+ // Element represents a slice.
+ case (elSmi: Smi): {
+ // The slice's match start and end is either encoded as one or two
+ // smis. A positive smi indicates a single smi encoding (see
+ // ReplacementStringBuilder::AddSubjectSlice()).
+ if (elSmi > 0) {
+ // For single smi encoding, see
+ // StringBuilderSubstringLength::encode() and
+ // StringBuilderSubstringPosition::encode().
+ const elInt: intptr = Convert<intptr>(elSmi);
+ const newMatchStart: intptr = (elInt >> 11) + (elInt & 0x7FF);
+ matchStart = Convert<Smi>(newMatchStart);
+ } else {
+ // For two smi encoding, the length is negative followed by the
+ // match start.
+ const nextEl: Smi = UnsafeCast<Smi>(matchesElements.objects[++i]);
+ matchStart = nextEl - elSmi;
}
}
+ // Element represents the matched substring, which is then passed to the
+ // replace function.
+ case (elString: String): {
+ const replacementObj: JSAny =
+ Call(context, replaceFn, Undefined, elString, matchStart, string);
+ const replacement: String = ToString_Inline(replacementObj);
+ matchesElements.objects[i] = replacement;
+ matchStart += elString.length_smi;
+ }
+ case (Object): deferred {
+ unreachable;
+ }
}
}
+}
- transitioning macro
- RegExpReplaceCallableWithExplicitCaptures(implicit context: Context)(
- matchesElements: FixedArray, matchesLength: intptr, replaceFn: Callable) {
- for (let i: intptr = 0; i < matchesLength; i++) {
- const elArray =
- Cast<JSArray>(matchesElements.objects[i]) otherwise continue;
-
- // The JSArray is expanded into the function args by Reflect.apply().
- // TODO(jgruber): Remove indirection through Call->ReflectApply.
- const replacementObj: JSAny = Call(
- context, GetReflectApply(), Undefined, replaceFn, Undefined, elArray);
-
- // Overwrite the i'th element in the results with the string
- // we got back from the callback function.
- matchesElements.objects[i] = ToString_Inline(replacementObj);
- }
+transitioning macro
+RegExpReplaceCallableWithExplicitCaptures(implicit context: Context)(
+ matchesElements: FixedArray, matchesLength: intptr, replaceFn: Callable) {
+ for (let i: intptr = 0; i < matchesLength; i++) {
+ const elArray =
+ Cast<JSArray>(matchesElements.objects[i]) otherwise continue;
+
+ // The JSArray is expanded into the function args by Reflect.apply().
+ // TODO(jgruber): Remove indirection through Call->ReflectApply.
+ const replacementObj: JSAny = Call(
+ context, GetReflectApply(), Undefined, replaceFn, Undefined, elArray);
+
+ // Overwrite the i'th element in the results with the string
+ // we got back from the callback function.
+ matchesElements.objects[i] = ToString_Inline(replacementObj);
}
+}
- transitioning macro RegExpReplaceFastGlobalCallable(implicit context:
- Context)(
- regexp: FastJSRegExp, string: String, replaceFn: Callable): String {
- regexp.lastIndex = 0;
-
- const kInitialCapacity: intptr = 16;
- const kInitialLength: Smi = 0;
- const result: Null|JSArray = RegExpExecMultiple(
- regexp, string, GetRegExpLastMatchInfo(),
- AllocateJSArray(
- ElementsKind::PACKED_ELEMENTS, GetFastPackedElementsJSArrayMap(),
- kInitialCapacity, kInitialLength));
-
- regexp.lastIndex = 0;
-
- // If no matches, return the subject string.
- if (result == Null) return string;
-
- const matches: JSArray = UnsafeCast<JSArray>(result);
- const matchesLength: Smi = Cast<Smi>(matches.length) otherwise unreachable;
- const matchesLengthInt: intptr = Convert<intptr>(matchesLength);
- const matchesElements: FixedArray =
- UnsafeCast<FixedArray>(matches.elements);
-
- // Reload last match info since it might have changed.
- const nofCaptures: Smi = GetRegExpLastMatchInfo().NumberOfCaptures();
-
- // If the number of captures is two then there are no explicit captures in
- // the regexp, just the implicit capture that captures the whole match. In
- // this case we can simplify quite a bit and end up with something faster.
- if (nofCaptures == 2) {
- RegExpReplaceCallableNoExplicitCaptures(
- matchesElements, matchesLengthInt, string, replaceFn);
- } else {
- RegExpReplaceCallableWithExplicitCaptures(
- matchesElements, matchesLengthInt, replaceFn);
- }
-
- return StringBuilderConcat(matches, matchesLength, string);
+transitioning macro RegExpReplaceFastGlobalCallable(implicit context: Context)(
+ regexp: FastJSRegExp, string: String, replaceFn: Callable): String {
+ regexp.lastIndex = 0;
+
+ const kInitialCapacity: intptr = 16;
+ const kInitialLength: Smi = 0;
+ const result: Null|JSArray = RegExpExecMultiple(
+ regexp, string, GetRegExpLastMatchInfo(),
+ AllocateJSArray(
+ ElementsKind::PACKED_ELEMENTS, GetFastPackedElementsJSArrayMap(),
+ kInitialCapacity, kInitialLength));
+
+ regexp.lastIndex = 0;
+
+ // If no matches, return the subject string.
+ if (result == Null) return string;
+
+ const matches: JSArray = UnsafeCast<JSArray>(result);
+ const matchesLength: Smi = Cast<Smi>(matches.length) otherwise unreachable;
+ const matchesLengthInt: intptr = Convert<intptr>(matchesLength);
+ const matchesElements: FixedArray = UnsafeCast<FixedArray>(matches.elements);
+
+ // Reload last match info since it might have changed.
+ const nofCaptures: Smi = GetRegExpLastMatchInfo().NumberOfCaptures();
+
+ // If the number of captures is two then there are no explicit captures in
+ // the regexp, just the implicit capture that captures the whole match. In
+ // this case we can simplify quite a bit and end up with something faster.
+ if (nofCaptures == 2) {
+ RegExpReplaceCallableNoExplicitCaptures(
+ matchesElements, matchesLengthInt, string, replaceFn);
+ } else {
+ RegExpReplaceCallableWithExplicitCaptures(
+ matchesElements, matchesLengthInt, replaceFn);
}
- transitioning macro RegExpReplaceFastString(implicit context: Context)(
- regexp: JSRegExp, string: String, replaceString: String): String {
- // The fast path is reached only if {receiver} is an unmodified JSRegExp
- // instance, {replace_value} is non-callable, and ToString({replace_value})
- // does not contain '$', i.e. we're doing a simple string replacement.
- let result: String = kEmptyString;
- let lastMatchEnd: Smi = 0;
- let unicode: bool = false;
- const replaceLength: Smi = replaceString.length_smi;
- const fastRegexp = UnsafeCast<FastJSRegExp>(regexp);
- const global: bool = fastRegexp.global;
-
- if (global) {
- unicode = fastRegexp.unicode;
- fastRegexp.lastIndex = 0;
- }
-
- while (true) {
- const match: RegExpMatchInfo =
- RegExpPrototypeExecBodyWithoutResultFast(regexp, string)
- otherwise break;
- const matchStart: Smi = match.GetStartOfCapture(0);
- const matchEnd: Smi = match.GetEndOfCapture(0);
-
- // TODO(jgruber): We could skip many of the checks that using SubString
- // here entails.
- result = result + SubString(string, lastMatchEnd, matchStart);
- lastMatchEnd = matchEnd;
-
- if (replaceLength != 0) result = result + replaceString;
-
- // Non-global case ends here after the first replacement.
- if (!global) break;
-
- // If match is the empty string, we have to increment lastIndex.
- if (matchEnd == matchStart) {
- typeswitch (regexp) {
- case (fastRegexp: FastJSRegExp): {
- fastRegexp.lastIndex =
- AdvanceStringIndexFast(string, fastRegexp.lastIndex, unicode);
- }
- case (Object): {
- const lastIndex: JSAny = SlowLoadLastIndex(regexp);
- const thisIndex: Number = ToLength_Inline(lastIndex);
- const nextIndex: Number =
- AdvanceStringIndexSlow(string, thisIndex, unicode);
- SlowStoreLastIndex(regexp, nextIndex);
- }
- }
- }
- }
+ return StringBuilderConcat(matches, matchesLength, string);
+}
- return result + SubString(string, lastMatchEnd, string.length_smi);
+transitioning macro RegExpReplaceFastString(implicit context: Context)(
+ regexp: JSRegExp, string: String, replaceString: String): String {
+ // The fast path is reached only if {receiver} is an unmodified JSRegExp
+ // instance, {replace_value} is non-callable, and ToString({replace_value})
+ // does not contain '$', i.e. we're doing a simple string replacement.
+ let result: String = kEmptyString;
+ let lastMatchEnd: Smi = 0;
+ let unicode: bool = false;
+ const replaceLength: Smi = replaceString.length_smi;
+ const fastRegexp = UnsafeCast<FastJSRegExp>(regexp);
+ const global: bool = fastRegexp.global;
+
+ if (global) {
+ unicode = fastRegexp.unicode;
+ fastRegexp.lastIndex = 0;
}
- transitioning builtin RegExpReplace(implicit context: Context)(
- regexp: FastJSRegExp, string: String, replaceValue: JSAny): String {
- // TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are
- // from Torque.
- assert(Is<FastJSRegExp>(regexp));
-
- // 2. Is {replace_value} callable?
- typeswitch (replaceValue) {
- case (replaceFn: Callable): {
- return regexp.global ?
- RegExpReplaceFastGlobalCallable(regexp, string, replaceFn) :
- StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn);
- }
- case (JSAny): {
- const stableRegexp: JSRegExp = regexp;
- const replaceString: String = ToString_Inline(replaceValue);
-
- try {
- // ToString(replaceValue) could potentially change the shape of the
- // RegExp object. Recheck that we are still on the fast path and bail
- // to runtime otherwise.
- const fastRegexp = Cast<FastJSRegExp>(stableRegexp) otherwise Runtime;
- if (StringIndexOf(
- replaceString, SingleCharacterStringConstant('$'), 0) != -1) {
- goto Runtime;
- }
-
- return RegExpReplaceFastString(fastRegexp, string, replaceString);
+ while (true) {
+ const match: RegExpMatchInfo =
+ RegExpPrototypeExecBodyWithoutResultFast(regexp, string)
+ otherwise break;
+ const matchStart: Smi = match.GetStartOfCapture(0);
+ const matchEnd: Smi = match.GetEndOfCapture(0);
+
+ // TODO(jgruber): We could skip many of the checks that using SubString
+ // here entails.
+ result = result + SubString(string, lastMatchEnd, matchStart);
+ lastMatchEnd = matchEnd;
+
+ if (replaceLength != 0) result = result + replaceString;
+
+ // Non-global case ends here after the first replacement.
+ if (!global) break;
+
+ // If match is the empty string, we have to increment lastIndex.
+ if (matchEnd == matchStart) {
+ typeswitch (regexp) {
+ case (fastRegexp: FastJSRegExp): {
+ fastRegexp.lastIndex =
+ AdvanceStringIndexFast(string, fastRegexp.lastIndex, unicode);
}
- label Runtime deferred {
- return RegExpReplaceRT(context, stableRegexp, string, replaceString);
+ case (Object): {
+ const lastIndex: JSAny = SlowLoadLastIndex(regexp);
+ const thisIndex: Number = ToLength_Inline(lastIndex);
+ const nextIndex: Number =
+ AdvanceStringIndexSlow(string, thisIndex, unicode);
+ SlowStoreLastIndex(regexp, nextIndex);
}
}
}
}
- const kRegExpReplaceCalledOnSlowRegExp: constexpr int31
- generates 'v8::Isolate::kRegExpReplaceCalledOnSlowRegExp';
-
- transitioning javascript builtin RegExpPrototypeReplace(
- js-implicit context: NativeContext,
- receiver: JSAny)(...arguments): JSAny {
- const methodName: constexpr string = 'RegExp.prototype.@@replace';
-
- // RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic:
- //
- // if (!IsFastRegExp(receiver)) CallRuntime(RegExpReplace)
- // if (IsCallable(replace)) {
- // if (IsGlobal(receiver)) {
- // // Called 'fast-path' but contains several runtime calls.
- // RegExpReplaceFastGlobalCallable()
- // } else {
- // CallRuntime(StringReplaceNonGlobalRegExpWithFunction)
- // }
- // } else {
- // if (replace.contains("$")) {
- // CallRuntime(RegExpReplace)
- // } else {
- // RegExpReplaceFastString()
- // }
- // }
-
- const string: JSAny = arguments[0];
- const replaceValue: JSAny = arguments[1];
-
- // Let rx be the this value.
- // If Type(rx) is not Object, throw a TypeError exception.
- const rx = Cast<JSReceiver>(receiver)
- otherwise ThrowTypeError(
- MessageTemplate::kIncompatibleMethodReceiver, methodName);
-
- // Let S be ? ToString(string).
- const s = ToString_Inline(string);
-
- // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
- try {
- const fastRx: FastJSRegExp = Cast<FastJSRegExp>(rx) otherwise Runtime;
- return RegExpReplace(fastRx, s, replaceValue);
+ return result + SubString(string, lastMatchEnd, string.length_smi);
+}
+
+transitioning builtin RegExpReplace(implicit context: Context)(
+ regexp: FastJSRegExp, string: String, replaceValue: JSAny): String {
+ // TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are
+ // from Torque.
+ assert(Is<FastJSRegExp>(regexp));
+
+ // 2. Is {replace_value} callable?
+ typeswitch (replaceValue) {
+ case (replaceFn: Callable): {
+ return regexp.global ?
+ RegExpReplaceFastGlobalCallable(regexp, string, replaceFn) :
+ StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn);
}
- label Runtime deferred {
- IncrementUseCounter(
- context, SmiConstant(kRegExpReplaceCalledOnSlowRegExp));
- return RegExpReplaceRT(context, rx, s, replaceValue);
+ case (JSAny): {
+ const stableRegexp: JSRegExp = regexp;
+ const replaceString: String = ToString_Inline(replaceValue);
+
+ try {
+ // ToString(replaceValue) could potentially change the shape of the
+ // RegExp object. Recheck that we are still on the fast path and bail
+ // to runtime otherwise.
+ const fastRegexp = Cast<FastJSRegExp>(stableRegexp) otherwise Runtime;
+ if (StringIndexOf(
+ replaceString, SingleCharacterStringConstant('$'), 0) != -1) {
+ goto Runtime;
+ }
+
+ return RegExpReplaceFastString(fastRegexp, string, replaceString);
+ } label Runtime deferred {
+ return RegExpReplaceRT(context, stableRegexp, string, replaceString);
+ }
}
}
+}
+const kRegExpReplaceCalledOnSlowRegExp: constexpr int31
+ generates 'v8::Isolate::kRegExpReplaceCalledOnSlowRegExp';
+
+transitioning javascript builtin RegExpPrototypeReplace(
+ js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
+ const methodName: constexpr string = 'RegExp.prototype.@@replace';
+
+ // RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic:
+ //
+ // if (!IsFastRegExp(receiver)) CallRuntime(RegExpReplace)
+ // if (IsCallable(replace)) {
+ // if (IsGlobal(receiver)) {
+ // // Called 'fast-path' but contains several runtime calls.
+ // RegExpReplaceFastGlobalCallable()
+ // } else {
+ // CallRuntime(StringReplaceNonGlobalRegExpWithFunction)
+ // }
+ // } else {
+ // if (replace.contains("$")) {
+ // CallRuntime(RegExpReplace)
+ // } else {
+ // RegExpReplaceFastString()
+ // }
+ // }
+
+ const string: JSAny = arguments[0];
+ const replaceValue: JSAny = arguments[1];
+
+ // Let rx be the this value.
+ // If Type(rx) is not Object, throw a TypeError exception.
+ const rx = Cast<JSReceiver>(receiver)
+ otherwise ThrowTypeError(
+ MessageTemplate::kIncompatibleMethodReceiver, methodName);
+
+ // Let S be ? ToString(string).
+ const s = ToString_Inline(string);
+
+ // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
+ try {
+ const fastRx: FastJSRegExp = Cast<FastJSRegExp>(rx) otherwise Runtime;
+ return RegExpReplace(fastRx, s, replaceValue);
+ } label Runtime deferred {
+ IncrementUseCounter(context, SmiConstant(kRegExpReplaceCalledOnSlowRegExp));
+ return RegExpReplaceRT(context, rx, s, replaceValue);
+ }
+}
}