Commit a10b4712 authored by jgruber's avatar jgruber Committed by Commit bot

[regexp] Port remaining JS functions in regexp.js

This ports RegExpInitialize, IsRegExp, InternalMatch and InternalReplace to C++
/ TurboFan. InternalMatch is in TurboFan because it calls RegExpExecStub and
needs to construct a RegExpResult (which are, respectively, a PlatformStub and
a CodeStubAssembler function).

Except for LastMatchInfo (and GetSubstitution, which could be moved to string.js
anytime), regexp.js is now completely empty.

BUG=v8:5339

Review-Url: https://codereview.chromium.org/2409513003
Cr-Commit-Position: refs/heads/master@{#40277}
parent 34e0596a
...@@ -1865,6 +1865,17 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1865,6 +1865,17 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
initial_map->set_unused_property_fields(0); initial_map->set_unused_property_fields(0);
initial_map->set_instance_size(initial_map->instance_size() + initial_map->set_instance_size(initial_map->instance_size() +
num_fields * kPointerSize); num_fields * kPointerSize);
{ // Internal: RegExpInternalMatch
Handle<JSFunction> function =
factory->NewFunction(isolate->factory()->empty_string(),
isolate->builtins()->RegExpInternalMatch(),
JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->shared()->set_internal_formal_parameter_count(2);
function->shared()->set_length(2);
function->shared()->set_native(true);
isolate->native_context()->set(Context::REGEXP_INTERNAL_MATCH, *function);
}
} }
{ // -- E r r o r { // -- E r r o r
......
...@@ -1655,5 +1655,63 @@ void Builtins::Generate_RegExpPrototypeReplace(CodeStubAssembler* a) { ...@@ -1655,5 +1655,63 @@ void Builtins::Generate_RegExpPrototypeReplace(CodeStubAssembler* a) {
} }
} }
namespace {
// TODO(jgruber): Replace this with a FixedArray.
compiler::Node* GetInternalMatchInfo(CodeStubAssembler* a,
compiler::Node* context) {
typedef compiler::Node Node;
const ElementsKind elements_kind = FAST_ELEMENTS;
Node* const native_context = a->LoadNativeContext(context);
Node* const array_map =
a->LoadJSArrayElementsMap(elements_kind, native_context);
Node* const capacity = a->IntPtrConstant(RegExpImpl::kLastMatchOverhead + 2);
Node* const allocation_site = nullptr;
Node* const smi_zero = a->SmiConstant(Smi::kZero);
return a->AllocateJSArray(elements_kind, array_map, capacity, smi_zero,
allocation_site,
CodeStubAssembler::INTPTR_PARAMETERS);
}
} // namespace
// Simple string matching functionality for internal use which does not modify
// the last match info.
void Builtins::Generate_RegExpInternalMatch(CodeStubAssembler* a) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Isolate* const isolate = a->isolate();
Node* const regexp = a->Parameter(1);
Node* const string = a->Parameter(2);
Node* const context = a->Parameter(5);
Node* const null = a->NullConstant();
Node* const smi_zero = a->SmiConstant(Smi::FromInt(0));
Node* const internal_match_info = GetInternalMatchInfo(a, context);
Callable exec_callable = CodeFactory::RegExpExec(isolate);
Node* const match_indices = a->CallStub(
exec_callable, context, regexp, string, smi_zero, internal_match_info);
Label if_matched(a), if_didnotmatch(a);
a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
a->Bind(&if_didnotmatch);
a->Return(null);
a->Bind(&if_matched);
{
Node* const match_elements = a->LoadElements(match_indices);
Node* result = ConstructNewResultFromMatchInfo(isolate, a, context,
match_elements, string);
a->Return(result);
}
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -575,6 +575,7 @@ namespace internal { ...@@ -575,6 +575,7 @@ namespace internal {
CPP(RegExpCapture8Getter) \ CPP(RegExpCapture8Getter) \
CPP(RegExpCapture9Getter) \ CPP(RegExpCapture9Getter) \
CPP(RegExpConstructor) \ CPP(RegExpConstructor) \
TFJ(RegExpInternalMatch, 3) \
CPP(RegExpInputGetter) \ CPP(RegExpInputGetter) \
CPP(RegExpInputSetter) \ CPP(RegExpInputSetter) \
CPP(RegExpLastMatchGetter) \ CPP(RegExpLastMatchGetter) \
......
...@@ -51,6 +51,7 @@ enum ContextLookupFlags { ...@@ -51,6 +51,7 @@ enum ContextLookupFlags {
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \ V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \ V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
V(OBJECT_KEYS, JSFunction, object_keys) \ V(OBJECT_KEYS, JSFunction, object_keys) \
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \ V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \ V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \ V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
......
...@@ -26,8 +26,6 @@ var GlobalString = global.String; ...@@ -26,8 +26,6 @@ var GlobalString = global.String;
var InstallFunctions = utils.InstallFunctions; var InstallFunctions = utils.InstallFunctions;
var InstallGetter = utils.InstallGetter; var InstallGetter = utils.InstallGetter;
var InternalArray = utils.InternalArray; var InternalArray = utils.InternalArray;
var InternalRegExpMatch;
var InternalRegExpReplace
var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty"); var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
var OverrideFunction = utils.OverrideFunction; var OverrideFunction = utils.OverrideFunction;
var patternSymbol = utils.ImportNow("intl_pattern_symbol"); var patternSymbol = utils.ImportNow("intl_pattern_symbol");
...@@ -39,8 +37,6 @@ var StringSubstring = GlobalString.prototype.substring; ...@@ -39,8 +37,6 @@ var StringSubstring = GlobalString.prototype.substring;
utils.Import(function(from) { utils.Import(function(from) {
ArrayJoin = from.ArrayJoin; ArrayJoin = from.ArrayJoin;
ArrayPush = from.ArrayPush; ArrayPush = from.ArrayPush;
InternalRegExpMatch = from.InternalRegExpMatch;
InternalRegExpReplace = from.InternalRegExpReplace;
}); });
// Utilities for definitions // Utilities for definitions
...@@ -249,7 +245,7 @@ function GetTimezoneNameLocationPartRE() { ...@@ -249,7 +245,7 @@ function GetTimezoneNameLocationPartRE() {
* Parameter locales is treated as a priority list. * Parameter locales is treated as a priority list.
*/ */
function supportedLocalesOf(service, locales, options) { function supportedLocalesOf(service, locales, options) {
if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) { if (IS_NULL(%regexp_internal_match(GetServiceRE(), service))) {
throw %make_error(kWrongServiceType, service); throw %make_error(kWrongServiceType, service);
} }
...@@ -297,7 +293,7 @@ function lookupSupportedLocalesOf(requestedLocales, availableLocales) { ...@@ -297,7 +293,7 @@ function lookupSupportedLocalesOf(requestedLocales, availableLocales) {
var matchedLocales = new InternalArray(); var matchedLocales = new InternalArray();
for (var i = 0; i < requestedLocales.length; ++i) { for (var i = 0; i < requestedLocales.length; ++i) {
// Remove -u- extension. // Remove -u- extension.
var locale = InternalRegExpReplace( var locale = %RegExpInternalReplace(
GetUnicodeExtensionRE(), requestedLocales[i], ''); GetUnicodeExtensionRE(), requestedLocales[i], '');
do { do {
if (!IS_UNDEFINED(availableLocales[locale])) { if (!IS_UNDEFINED(availableLocales[locale])) {
...@@ -407,7 +403,7 @@ function resolveLocale(service, requestedLocales, options) { ...@@ -407,7 +403,7 @@ function resolveLocale(service, requestedLocales, options) {
* lookup algorithm. * lookup algorithm.
*/ */
function lookupMatcher(service, requestedLocales) { function lookupMatcher(service, requestedLocales) {
if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) { if (IS_NULL(%regexp_internal_match(GetServiceRE(), service))) {
throw %make_error(kWrongServiceType, service); throw %make_error(kWrongServiceType, service);
} }
...@@ -418,12 +414,12 @@ function lookupMatcher(service, requestedLocales) { ...@@ -418,12 +414,12 @@ function lookupMatcher(service, requestedLocales) {
for (var i = 0; i < requestedLocales.length; ++i) { for (var i = 0; i < requestedLocales.length; ++i) {
// Remove all extensions. // Remove all extensions.
var locale = InternalRegExpReplace( var locale = %RegExpInternalReplace(
GetAnyExtensionRE(), requestedLocales[i], ''); GetAnyExtensionRE(), requestedLocales[i], '');
do { do {
if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) { if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) {
// Return the resolved locale and extension. // Return the resolved locale and extension.
var extensionMatch = InternalRegExpMatch( var extensionMatch = %regexp_internal_match(
GetUnicodeExtensionRE(), requestedLocales[i]); GetUnicodeExtensionRE(), requestedLocales[i]);
var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0]; var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
return {'locale': locale, 'extension': extension, 'position': i}; return {'locale': locale, 'extension': extension, 'position': i};
...@@ -621,7 +617,7 @@ function getOptimalLanguageTag(original, resolved) { ...@@ -621,7 +617,7 @@ function getOptimalLanguageTag(original, resolved) {
// Preserve extensions of resolved locale, but swap base tags with original. // Preserve extensions of resolved locale, but swap base tags with original.
var resolvedBase = new GlobalRegExp('^' + locales[1].base, 'g'); var resolvedBase = new GlobalRegExp('^' + locales[1].base, 'g');
return InternalRegExpReplace(resolvedBase, resolved, locales[0].base); return %RegExpInternalReplace(resolvedBase, resolved, locales[0].base);
} }
...@@ -636,7 +632,7 @@ function getAvailableLocalesOf(service) { ...@@ -636,7 +632,7 @@ function getAvailableLocalesOf(service) {
for (var i in available) { for (var i in available) {
if (HAS_OWN_PROPERTY(available, i)) { if (HAS_OWN_PROPERTY(available, i)) {
var parts = InternalRegExpMatch( var parts = %regexp_internal_match(
/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, i); /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, i);
if (!IS_NULL(parts)) { if (!IS_NULL(parts)) {
// Build xx-ZZ. We don't care about the actual value, // Build xx-ZZ. We don't care about the actual value,
...@@ -708,7 +704,7 @@ function toTitleCaseWord(word) { ...@@ -708,7 +704,7 @@ function toTitleCaseWord(word) {
* 'of', 'au' and 'es' are special-cased and lowercased. * 'of', 'au' and 'es' are special-cased and lowercased.
*/ */
function toTitleCaseTimezoneLocation(location) { function toTitleCaseTimezoneLocation(location) {
var match = InternalRegExpMatch(GetTimezoneNameLocationPartRE(), location) var match = %regexp_internal_match(GetTimezoneNameLocationPartRE(), location)
if (IS_NULL(match)) throw %make_range_error(kExpectedLocation, location); if (IS_NULL(match)) throw %make_range_error(kExpectedLocation, location);
var result = toTitleCaseWord(match[1]); var result = toTitleCaseWord(match[1]);
...@@ -743,7 +739,7 @@ function canonicalizeLanguageTag(localeID) { ...@@ -743,7 +739,7 @@ function canonicalizeLanguageTag(localeID) {
// Optimize for the most common case; a language code alone in // Optimize for the most common case; a language code alone in
// the canonical form/lowercase (e.g. "en", "fil"). // the canonical form/lowercase (e.g. "en", "fil").
if (IS_STRING(localeID) && if (IS_STRING(localeID) &&
!IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { !IS_NULL(%regexp_internal_match(/^[a-z]{2,3}$/, localeID))) {
return localeID; return localeID;
} }
...@@ -821,7 +817,7 @@ function initializeLocaleList(locales) { ...@@ -821,7 +817,7 @@ function initializeLocaleList(locales) {
*/ */
function isStructuallyValidLanguageTag(locale) { function isStructuallyValidLanguageTag(locale) {
// Check if it's well-formed, including grandfadered tags. // Check if it's well-formed, including grandfadered tags.
if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { if (IS_NULL(%regexp_internal_match(GetLanguageTagRE(), locale))) {
return false; return false;
} }
...@@ -843,7 +839,7 @@ function isStructuallyValidLanguageTag(locale) { ...@@ -843,7 +839,7 @@ function isStructuallyValidLanguageTag(locale) {
var parts = %StringSplit(locale, '-', kMaxUint32); var parts = %StringSplit(locale, '-', kMaxUint32);
for (var i = 1; i < parts.length; i++) { for (var i = 1; i < parts.length; i++) {
var value = parts[i]; var value = parts[i];
if (!IS_NULL(InternalRegExpMatch(GetLanguageVariantRE(), value)) && if (!IS_NULL(%regexp_internal_match(GetLanguageVariantRE(), value)) &&
extensions.length === 0) { extensions.length === 0) {
if (%ArrayIndexOf(variants, value, 0) === -1) { if (%ArrayIndexOf(variants, value, 0) === -1) {
%_Call(ArrayPush, variants, value); %_Call(ArrayPush, variants, value);
...@@ -852,7 +848,7 @@ function isStructuallyValidLanguageTag(locale) { ...@@ -852,7 +848,7 @@ function isStructuallyValidLanguageTag(locale) {
} }
} }
if (!IS_NULL(InternalRegExpMatch(GetLanguageSingletonRE(), value))) { if (!IS_NULL(%regexp_internal_match(GetLanguageSingletonRE(), value))) {
if (%ArrayIndexOf(extensions, value, 0) === -1) { if (%ArrayIndexOf(extensions, value, 0) === -1) {
%_Call(ArrayPush, extensions, value); %_Call(ArrayPush, extensions, value);
} else { } else {
...@@ -1121,7 +1117,7 @@ AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator'); ...@@ -1121,7 +1117,7 @@ AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator');
*/ */
function isWellFormedCurrencyCode(currency) { function isWellFormedCurrencyCode(currency) {
return typeof currency == "string" && currency.length == 3 && return typeof currency == "string" && currency.length == 3 &&
IS_NULL(InternalRegExpMatch(/[^A-Za-z]/, currency)); IS_NULL(%regexp_internal_match(/[^A-Za-z]/, currency));
} }
...@@ -1439,57 +1435,57 @@ function appendToLDMLString(option, pairs) { ...@@ -1439,57 +1435,57 @@ function appendToLDMLString(option, pairs) {
*/ */
function fromLDMLString(ldmlString) { function fromLDMLString(ldmlString) {
// First remove '' quoted text, so we lose 'Uhr' strings. // First remove '' quoted text, so we lose 'Uhr' strings.
ldmlString = InternalRegExpReplace(GetQuotedStringRE(), ldmlString, ''); ldmlString = %RegExpInternalReplace(GetQuotedStringRE(), ldmlString, '');
var options = {}; var options = {};
var match = InternalRegExpMatch(/E{3,5}/, ldmlString); var match = %regexp_internal_match(/E{3,5}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'}); options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
match = InternalRegExpMatch(/G{3,5}/, ldmlString); match = %regexp_internal_match(/G{3,5}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'}); options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
match = InternalRegExpMatch(/y{1,2}/, ldmlString); match = %regexp_internal_match(/y{1,2}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'year', match, {y: 'numeric', yy: '2-digit'}); options, 'year', match, {y: 'numeric', yy: '2-digit'});
match = InternalRegExpMatch(/M{1,5}/, ldmlString); match = %regexp_internal_match(/M{1,5}/, ldmlString);
options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit', options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'}); M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
// Sometimes we get L instead of M for month - standalone name. // Sometimes we get L instead of M for month - standalone name.
match = InternalRegExpMatch(/L{1,5}/, ldmlString); match = %regexp_internal_match(/L{1,5}/, ldmlString);
options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit', options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'}); L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
match = InternalRegExpMatch(/d{1,2}/, ldmlString); match = %regexp_internal_match(/d{1,2}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'day', match, {d: 'numeric', dd: '2-digit'}); options, 'day', match, {d: 'numeric', dd: '2-digit'});
match = InternalRegExpMatch(/h{1,2}/, ldmlString); match = %regexp_internal_match(/h{1,2}/, ldmlString);
if (match !== null) { if (match !== null) {
options['hour12'] = true; options['hour12'] = true;
} }
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'hour', match, {h: 'numeric', hh: '2-digit'}); options, 'hour', match, {h: 'numeric', hh: '2-digit'});
match = InternalRegExpMatch(/H{1,2}/, ldmlString); match = %regexp_internal_match(/H{1,2}/, ldmlString);
if (match !== null) { if (match !== null) {
options['hour12'] = false; options['hour12'] = false;
} }
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'hour', match, {H: 'numeric', HH: '2-digit'}); options, 'hour', match, {H: 'numeric', HH: '2-digit'});
match = InternalRegExpMatch(/m{1,2}/, ldmlString); match = %regexp_internal_match(/m{1,2}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'minute', match, {m: 'numeric', mm: '2-digit'}); options, 'minute', match, {m: 'numeric', mm: '2-digit'});
match = InternalRegExpMatch(/s{1,2}/, ldmlString); match = %regexp_internal_match(/s{1,2}/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'second', match, {s: 'numeric', ss: '2-digit'}); options, 'second', match, {s: 'numeric', ss: '2-digit'});
match = InternalRegExpMatch(/z|zzzz/, ldmlString); match = %regexp_internal_match(/z|zzzz/, ldmlString);
options = appendToDateTimeObject( options = appendToDateTimeObject(
options, 'timeZoneName', match, {z: 'short', zzzz: 'long'}); options, 'timeZoneName', match, {z: 'short', zzzz: 'long'});
...@@ -1818,7 +1814,7 @@ function canonicalizeTimeZoneID(tzID) { ...@@ -1818,7 +1814,7 @@ function canonicalizeTimeZoneID(tzID) {
// We expect only _, '-' and / beside ASCII letters. // We expect only _, '-' and / beside ASCII letters.
// All inputs should conform to Area/Location(/Location)* from now on. // All inputs should conform to Area/Location(/Location)* from now on.
var match = InternalRegExpMatch(GetTimezoneNameCheckRE(), tzID); var match = %regexp_internal_match(GetTimezoneNameCheckRE(), tzID);
if (IS_NULL(match)) throw %make_range_error(kExpectedTimezoneID, tzID); if (IS_NULL(match)) throw %make_range_error(kExpectedTimezoneID, tzID);
var result = toTitleCaseTimezoneLocation(match[1]) + '/' + var result = toTitleCaseTimezoneLocation(match[1]) + '/' +
......
...@@ -8,14 +8,6 @@ ...@@ -8,14 +8,6 @@
%CheckIsBootstrapping(); %CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
var GlobalRegExp = global.RegExp;
var GlobalRegExpPrototype = GlobalRegExp.prototype;
var RegExpExecJS = GlobalRegExp.prototype.exec;
var matchSymbol = utils.ImportNow("match_symbol");
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Property of the builtins object for recording the result of the last // Property of the builtins object for recording the result of the last
...@@ -34,52 +26,6 @@ var RegExpLastMatchInfo = { ...@@ -34,52 +26,6 @@ var RegExpLastMatchInfo = {
CAPTURE1: 0 CAPTURE1: 0
}; };
// -------------------------------------------------------------------
// ES#sec-isregexp IsRegExp ( argument )
function IsRegExp(o) {
if (!IS_RECEIVER(o)) return false;
var is_regexp = o[matchSymbol];
if (!IS_UNDEFINED(is_regexp)) return TO_BOOLEAN(is_regexp);
return IS_REGEXP(o);
}
// ES#sec-regexpinitialize
// Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
function RegExpInitialize(object, pattern, flags) {
pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern);
flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags);
%RegExpInitializeAndCompile(object, pattern, flags);
return object;
}
// This is kind of performance sensitive, so we want to avoid unnecessary
// type checks on inputs. But we also don't want to inline it several times
// manually, so we use a macro :-)
macro RETURN_NEW_RESULT_FROM_MATCH_INFO(MATCHINFO, STRING)
var numResults = NUMBER_OF_CAPTURES(MATCHINFO) >> 1;
var start = MATCHINFO[CAPTURE0];
var end = MATCHINFO[CAPTURE1];
// Calculate the substring of the first match before creating the result array
// to avoid an unnecessary write barrier storing the first result.
var first = %_SubString(STRING, start, end);
var result = %_RegExpConstructResult(numResults, start, STRING);
result[0] = first;
if (numResults == 1) return result;
var j = REGEXP_FIRST_CAPTURE + 2;
for (var i = 1; i < numResults; i++) {
start = MATCHINFO[j++];
if (start != -1) {
end = MATCHINFO[j];
result[i] = %_SubString(STRING, start, end);
}
j++;
}
return result;
endmacro
// ES#sec-getsubstitution // ES#sec-getsubstitution
// GetSubstitution(matched, str, position, captures, replacement) // GetSubstitution(matched, str, position, captures, replacement)
// Expand the $-expressions in the string and return a new string with // Expand the $-expressions in the string and return a new string with
...@@ -169,40 +115,11 @@ function GetSubstitution(matched, string, position, captures, replacement) { ...@@ -169,40 +115,11 @@ function GetSubstitution(matched, string, position, captures, replacement) {
%InstallToContext(["regexp_last_match_info", RegExpLastMatchInfo]); %InstallToContext(["regexp_last_match_info", RegExpLastMatchInfo]);
// -------------------------------------------------------------------
// Internal
var InternalRegExpMatchInfo = {
REGEXP_NUMBER_OF_CAPTURES: 2,
REGEXP_LAST_SUBJECT: "",
REGEXP_LAST_INPUT: UNDEFINED,
CAPTURE0: 0,
CAPTURE1: 0
};
function InternalRegExpMatch(regexp, subject) {
var matchInfo = %_RegExpExec(regexp, subject, 0, InternalRegExpMatchInfo);
if (!IS_NULL(matchInfo)) {
RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, subject);
}
return null;
}
function InternalRegExpReplace(regexp, subject, replacement) {
return %StringReplaceGlobalRegExpWithString(
subject, regexp, replacement, InternalRegExpMatchInfo);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Exports // Exports
utils.Export(function(to) { utils.Export(function(to) {
to.GetSubstitution = GetSubstitution; to.GetSubstitution = GetSubstitution;
to.InternalRegExpMatch = InternalRegExpMatch;
to.InternalRegExpReplace = InternalRegExpReplace;
to.IsRegExp = IsRegExp;
to.RegExpInitialize = RegExpInitialize;
to.RegExpLastMatchInfo = RegExpLastMatchInfo;
}); });
}) })
...@@ -13,10 +13,8 @@ var ArrayJoin; ...@@ -13,10 +13,8 @@ var ArrayJoin;
var GetSubstitution; var GetSubstitution;
var GlobalRegExp = global.RegExp; var GlobalRegExp = global.RegExp;
var GlobalString = global.String; var GlobalString = global.String;
var IsRegExp;
var MaxSimple; var MaxSimple;
var MinSimple; var MinSimple;
var RegExpInitialize;
var matchSymbol = utils.ImportNow("match_symbol"); var matchSymbol = utils.ImportNow("match_symbol");
var replaceSymbol = utils.ImportNow("replace_symbol"); var replaceSymbol = utils.ImportNow("replace_symbol");
var searchSymbol = utils.ImportNow("search_symbol"); var searchSymbol = utils.ImportNow("search_symbol");
...@@ -25,10 +23,8 @@ var splitSymbol = utils.ImportNow("split_symbol"); ...@@ -25,10 +23,8 @@ var splitSymbol = utils.ImportNow("split_symbol");
utils.Import(function(from) { utils.Import(function(from) {
ArrayJoin = from.ArrayJoin; ArrayJoin = from.ArrayJoin;
GetSubstitution = from.GetSubstitution; GetSubstitution = from.GetSubstitution;
IsRegExp = from.IsRegExp;
MaxSimple = from.MaxSimple; MaxSimple = from.MaxSimple;
MinSimple = from.MinSimple; MinSimple = from.MinSimple;
RegExpInitialize = from.RegExpInitialize;
}); });
//------------------------------------------------------------------- //-------------------------------------------------------------------
...@@ -60,8 +56,7 @@ function StringMatchJS(pattern) { ...@@ -60,8 +56,7 @@ function StringMatchJS(pattern) {
var subject = TO_STRING(this); var subject = TO_STRING(this);
// Equivalent to RegExpCreate (ES#sec-regexpcreate) // Equivalent to RegExpCreate (ES#sec-regexpcreate)
var regexp = %_NewObject(GlobalRegExp, GlobalRegExp); var regexp = %RegExpCreate(pattern);
RegExpInitialize(regexp, pattern);
return regexp[matchSymbol](subject); return regexp[matchSymbol](subject);
} }
...@@ -143,8 +138,7 @@ function StringSearch(pattern) { ...@@ -143,8 +138,7 @@ function StringSearch(pattern) {
var subject = TO_STRING(this); var subject = TO_STRING(this);
// Equivalent to RegExpCreate (ES#sec-regexpcreate) // Equivalent to RegExpCreate (ES#sec-regexpcreate)
var regexp = %_NewObject(GlobalRegExp, GlobalRegExp); var regexp = %RegExpCreate(pattern);
RegExpInitialize(regexp, pattern);
return %_Call(regexp[searchSymbol], regexp, subject); return %_Call(regexp[searchSymbol], regexp, subject);
} }
......
...@@ -656,16 +656,11 @@ MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( ...@@ -656,16 +656,11 @@ MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString(
return *answer; return *answer;
} }
namespace {
RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { Object* StringReplaceGlobalRegExpWithStringHelper(
HandleScope scope(isolate); Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject,
DCHECK(args.length() == 4); Handle<String> replacement, Handle<JSObject> last_match_info) {
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3);
CHECK(regexp->GetFlags() & JSRegExp::kGlobal); CHECK(regexp->GetFlags() & JSRegExp::kGlobal);
CHECK(last_match_info->HasFastObjectElements()); CHECK(last_match_info->HasFastObjectElements());
...@@ -687,6 +682,20 @@ RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { ...@@ -687,6 +682,20 @@ RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
replacement, last_match_info); replacement, last_match_info);
} }
} // namespace
RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3);
return StringReplaceGlobalRegExpWithStringHelper(
isolate, regexp, subject, replacement, last_match_info);
}
RUNTIME_FUNCTION(Runtime_StringSplit) { RUNTIME_FUNCTION(Runtime_StringSplit) {
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
...@@ -769,6 +778,32 @@ RUNTIME_FUNCTION(Runtime_StringSplit) { ...@@ -769,6 +778,32 @@ RUNTIME_FUNCTION(Runtime_StringSplit) {
return *result; return *result;
} }
// ES##sec-regexpcreate
// RegExpCreate ( P, F )
RUNTIME_FUNCTION(Runtime_RegExpCreate) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, source_object, 0);
Handle<String> source;
if (source_object->IsUndefined(isolate)) {
source = isolate->factory()->empty_string();
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, source, Object::ToString(isolate, source_object));
}
Handle<Map> map(isolate->regexp_function()->initial_map());
Handle<JSRegExp> regexp =
Handle<JSRegExp>::cast(isolate->factory()->NewJSObjectFromMap(map));
JSRegExp::Flags flags = JSRegExp::kNone;
RETURN_FAILURE_ON_EXCEPTION(isolate,
JSRegExp::Initialize(regexp, source, flags));
return *regexp;
}
RUNTIME_FUNCTION(Runtime_RegExpExec) { RUNTIME_FUNCTION(Runtime_RegExpExec) {
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -835,6 +870,22 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) { ...@@ -835,6 +870,22 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
return *regexp; return *regexp;
} }
RUNTIME_FUNCTION(Runtime_RegExpInternalReplace) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
static const int kInitialMatchSlots = 2;
Handle<JSArray> internal_match_info = isolate->factory()->NewJSArray(
FAST_ELEMENTS, 0, RegExpImpl::kLastMatchOverhead + kInitialMatchSlots,
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
return StringReplaceGlobalRegExpWithStringHelper(
isolate, regexp, subject, replacement, internal_match_info);
}
namespace { namespace {
class MatchInfoBackedMatch : public String::Match { class MatchInfoBackedMatch : public String::Match {
......
...@@ -459,12 +459,14 @@ namespace internal { ...@@ -459,12 +459,14 @@ namespace internal {
#define FOR_EACH_INTRINSIC_REGEXP(F) \ #define FOR_EACH_INTRINSIC_REGEXP(F) \
F(StringReplaceGlobalRegExpWithString, 4, 1) \ F(StringReplaceGlobalRegExpWithString, 4, 1) \
F(StringSplit, 3, 1) \ F(StringSplit, 3, 1) \
F(RegExpCreate, 1, 1) \
F(RegExpExec, 4, 1) \ F(RegExpExec, 4, 1) \
F(RegExpFlags, 1, 1) \ F(RegExpFlags, 1, 1) \
F(RegExpReplace, 3, 1) \ F(RegExpReplace, 3, 1) \
F(RegExpSource, 1, 1) \ F(RegExpSource, 1, 1) \
F(RegExpConstructResult, 3, 1) \ F(RegExpConstructResult, 3, 1) \
F(RegExpInitializeAndCompile, 3, 1) \ F(RegExpInitializeAndCompile, 3, 1) \
F(RegExpInternalReplace, 3, 1) \
F(RegExpExecReThrow, 4, 1) \ F(RegExpExecReThrow, 4, 1) \
F(IsRegExp, 1, 1) F(IsRegExp, 1, 1)
......
...@@ -78,7 +78,7 @@ bytecodes: [ ...@@ -78,7 +78,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0), /* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(9), B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(1), B(Star), R(1),
B(CallJSRuntime), U8(147), R(0), U8(2), B(CallJSRuntime), U8(148), R(0), U8(2),
/* 44 S> */ B(Return), /* 44 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment