11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include 'src/builtins/builtins-regexp-gen.h' 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_cinamespace regexp { 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst kATOM: constexpr int31 101cb0ef41Sopenharmony_ci generates 'JSRegExp::ATOM'; 111cb0ef41Sopenharmony_ciconst kTagIndex: constexpr int31 121cb0ef41Sopenharmony_ci generates 'JSRegExp::kTagIndex'; 131cb0ef41Sopenharmony_ciconst kAtomPatternIndex: constexpr int31 141cb0ef41Sopenharmony_ci generates 'JSRegExp::kAtomPatternIndex'; 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ciextern transitioning macro RegExpBuiltinsAssembler::FlagGetter( 171cb0ef41Sopenharmony_ci implicit context: Context)(Object, constexpr Flag, constexpr bool): bool; 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciextern macro UnsafeLoadFixedArrayElement( 201cb0ef41Sopenharmony_ci RegExpMatchInfo, constexpr int31): Object; 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_citransitioning macro RegExpPrototypeMatchBody(implicit context: Context)( 231cb0ef41Sopenharmony_ci regexp: JSReceiver, string: String, isFastPath: constexpr bool): JSAny { 241cb0ef41Sopenharmony_ci if constexpr (isFastPath) { 251cb0ef41Sopenharmony_ci dcheck(Is<FastJSRegExp>(regexp)); 261cb0ef41Sopenharmony_ci } 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci const isGlobal: bool = FlagGetter(regexp, Flag::kGlobal, isFastPath); 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci if (!isGlobal) { 311cb0ef41Sopenharmony_ci return isFastPath ? RegExpPrototypeExecBodyFast(regexp, string) : 321cb0ef41Sopenharmony_ci RegExpExec(regexp, string); 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci dcheck(isGlobal); 361cb0ef41Sopenharmony_ci const isUnicode: bool = FlagGetter(regexp, Flag::kUnicode, isFastPath); 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci StoreLastIndex(regexp, 0, isFastPath); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci // Allocate an array to store the resulting match strings. 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci let array = growable_fixed_array::NewGrowableFixedArray(); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci // Check if the regexp is an ATOM type. If so, then keep the literal string 451cb0ef41Sopenharmony_ci // to search for so that we can avoid calling substring in the loop below. 461cb0ef41Sopenharmony_ci let atom: bool = false; 471cb0ef41Sopenharmony_ci let searchString: String = EmptyStringConstant(); 481cb0ef41Sopenharmony_ci if constexpr (isFastPath) { 491cb0ef41Sopenharmony_ci const maybeAtomRegexp = UnsafeCast<JSRegExp>(regexp); 501cb0ef41Sopenharmony_ci const data = UnsafeCast<FixedArray>(maybeAtomRegexp.data); 511cb0ef41Sopenharmony_ci if (UnsafeCast<Smi>(data.objects[kTagIndex]) == kATOM) { 521cb0ef41Sopenharmony_ci searchString = UnsafeCast<String>(data.objects[kAtomPatternIndex]); 531cb0ef41Sopenharmony_ci atom = true; 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci while (true) { 581cb0ef41Sopenharmony_ci let match: String = EmptyStringConstant(); 591cb0ef41Sopenharmony_ci try { 601cb0ef41Sopenharmony_ci if constexpr (isFastPath) { 611cb0ef41Sopenharmony_ci // On the fast path, grab the matching string from the raw match index 621cb0ef41Sopenharmony_ci // array. 631cb0ef41Sopenharmony_ci const matchIndices: RegExpMatchInfo = 641cb0ef41Sopenharmony_ci RegExpPrototypeExecBodyWithoutResultFast( 651cb0ef41Sopenharmony_ci UnsafeCast<JSRegExp>(regexp), string) otherwise IfDidNotMatch; 661cb0ef41Sopenharmony_ci if (atom) { 671cb0ef41Sopenharmony_ci match = searchString; 681cb0ef41Sopenharmony_ci } else { 691cb0ef41Sopenharmony_ci const matchFrom = UnsafeLoadFixedArrayElement( 701cb0ef41Sopenharmony_ci matchIndices, kRegExpMatchInfoFirstCaptureIndex); 711cb0ef41Sopenharmony_ci const matchTo = UnsafeLoadFixedArrayElement( 721cb0ef41Sopenharmony_ci matchIndices, kRegExpMatchInfoFirstCaptureIndex + 1); 731cb0ef41Sopenharmony_ci match = SubString( 741cb0ef41Sopenharmony_ci string, UnsafeCast<Smi>(matchFrom), UnsafeCast<Smi>(matchTo)); 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci } else { 771cb0ef41Sopenharmony_ci dcheck(!isFastPath); 781cb0ef41Sopenharmony_ci const resultTemp = RegExpExec(regexp, string); 791cb0ef41Sopenharmony_ci if (resultTemp == Null) { 801cb0ef41Sopenharmony_ci goto IfDidNotMatch; 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci match = ToString_Inline(GetProperty(resultTemp, SmiConstant(0))); 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci goto IfDidMatch; 851cb0ef41Sopenharmony_ci } label IfDidNotMatch { 861cb0ef41Sopenharmony_ci return array.length == 0 ? Null : array.ToJSArray(); 871cb0ef41Sopenharmony_ci } label IfDidMatch { 881cb0ef41Sopenharmony_ci // Store the match, growing the fixed array if needed. 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci array.Push(match); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci // Advance last index if the match is the empty string. 931cb0ef41Sopenharmony_ci const matchLength: Smi = match.length_smi; 941cb0ef41Sopenharmony_ci if (matchLength != 0) { 951cb0ef41Sopenharmony_ci continue; 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci let lastIndex = LoadLastIndex(regexp, isFastPath); 981cb0ef41Sopenharmony_ci if constexpr (isFastPath) { 991cb0ef41Sopenharmony_ci dcheck(TaggedIsPositiveSmi(lastIndex)); 1001cb0ef41Sopenharmony_ci } else { 1011cb0ef41Sopenharmony_ci lastIndex = ToLength_Inline(lastIndex); 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci const newLastIndex: Number = AdvanceStringIndex( 1051cb0ef41Sopenharmony_ci string, UnsafeCast<Number>(lastIndex), isUnicode, isFastPath); 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci if constexpr (isFastPath) { 1081cb0ef41Sopenharmony_ci // On the fast path, we can be certain that lastIndex can never be 1091cb0ef41Sopenharmony_ci // incremented to overflow the Smi range since the maximal string 1101cb0ef41Sopenharmony_ci // length is less than the maximal Smi value. 1111cb0ef41Sopenharmony_ci StaticAssertStringLengthFitsSmi(); 1121cb0ef41Sopenharmony_ci dcheck(TaggedIsPositiveSmi(newLastIndex)); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci StoreLastIndex(regexp, newLastIndex, isFastPath); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci VerifiedUnreachable(); 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_citransitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)( 1231cb0ef41Sopenharmony_ci receiver: FastJSRegExp, string: String): JSAny { 1241cb0ef41Sopenharmony_ci return RegExpPrototypeMatchBody(receiver, string, true); 1251cb0ef41Sopenharmony_ci} 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_citransitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)( 1281cb0ef41Sopenharmony_ci receiver: JSReceiver, string: String): JSAny { 1291cb0ef41Sopenharmony_ci return RegExpPrototypeMatchBody(receiver, string, false); 1301cb0ef41Sopenharmony_ci} 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci// Helper that skips a few initial checks. and assumes... 1331cb0ef41Sopenharmony_ci// 1) receiver is a "fast" RegExp 1341cb0ef41Sopenharmony_ci// 2) pattern is a string 1351cb0ef41Sopenharmony_citransitioning builtin RegExpMatchFast(implicit context: Context)( 1361cb0ef41Sopenharmony_ci receiver: FastJSRegExp, string: String): JSAny { 1371cb0ef41Sopenharmony_ci return FastRegExpPrototypeMatchBody(receiver, string); 1381cb0ef41Sopenharmony_ci} 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci// ES#sec-regexp.prototype-@@match 1411cb0ef41Sopenharmony_ci// RegExp.prototype [ @@match ] ( string ) 1421cb0ef41Sopenharmony_citransitioning javascript builtin RegExpPrototypeMatch( 1431cb0ef41Sopenharmony_ci js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { 1441cb0ef41Sopenharmony_ci ThrowIfNotJSReceiver( 1451cb0ef41Sopenharmony_ci receiver, MessageTemplate::kIncompatibleMethodReceiver, 1461cb0ef41Sopenharmony_ci 'RegExp.prototype.@@match'); 1471cb0ef41Sopenharmony_ci const receiver = UnsafeCast<JSReceiver>(receiver); 1481cb0ef41Sopenharmony_ci const string: String = ToString_Inline(string); 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci // Strict: Reads global and unicode properties. 1511cb0ef41Sopenharmony_ci // TODO(jgruber): Handle slow flag accesses on the fast path and make this 1521cb0ef41Sopenharmony_ci // permissive. 1531cb0ef41Sopenharmony_ci const fastRegExp = Cast<FastJSRegExp>(receiver) 1541cb0ef41Sopenharmony_ci otherwise return SlowRegExpPrototypeMatchBody(receiver, string); 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci // TODO(pwong): Could be optimized to remove the overhead of calling the 1571cb0ef41Sopenharmony_ci // builtin (at the cost of a larger builtin). 1581cb0ef41Sopenharmony_ci return RegExpMatchFast(fastRegExp, string); 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci} 161