11cb0ef41Sopenharmony_ci// Copyright 2017 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_ci#include "src/builtins/builtins-constructor-gen.h" 81cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h" 91cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 101cb0ef41Sopenharmony_ci#include "src/builtins/growable-fixed-array-gen.h" 111cb0ef41Sopenharmony_ci#include "src/codegen/code-factory.h" 121cb0ef41Sopenharmony_ci#include "src/codegen/code-stub-assembler.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/macro-assembler.h" 141cb0ef41Sopenharmony_ci#include "src/common/globals.h" 151cb0ef41Sopenharmony_ci#include "src/execution/protectors.h" 161cb0ef41Sopenharmony_ci#include "src/heap/factory-inl.h" 171cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 181cb0ef41Sopenharmony_ci#include "src/objects/js-regexp-string-iterator.h" 191cb0ef41Sopenharmony_ci#include "src/objects/js-regexp.h" 201cb0ef41Sopenharmony_ci#include "src/objects/regexp-match-info.h" 211cb0ef41Sopenharmony_ci#include "src/regexp/regexp-flags.h" 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_cinamespace v8 { 241cb0ef41Sopenharmony_cinamespace internal { 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci// Tail calls the regular expression interpreter. 271cb0ef41Sopenharmony_ci// static 281cb0ef41Sopenharmony_civoid Builtins::Generate_RegExpInterpreterTrampoline(MacroAssembler* masm) { 291cb0ef41Sopenharmony_ci ExternalReference interpreter_code_entry = 301cb0ef41Sopenharmony_ci ExternalReference::re_match_for_call_from_js(); 311cb0ef41Sopenharmony_ci masm->Jump(interpreter_code_entry); 321cb0ef41Sopenharmony_ci} 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci// Tail calls the experimental regular expression engine. 351cb0ef41Sopenharmony_ci// static 361cb0ef41Sopenharmony_civoid Builtins::Generate_RegExpExperimentalTrampoline(MacroAssembler* masm) { 371cb0ef41Sopenharmony_ci ExternalReference interpreter_code_entry = 381cb0ef41Sopenharmony_ci ExternalReference::re_experimental_match_for_call_from_js(); 391cb0ef41Sopenharmony_ci masm->Jump(interpreter_code_entry); 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciTNode<Smi> RegExpBuiltinsAssembler::SmiZero() { return SmiConstant(0); } 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciTNode<IntPtrT> RegExpBuiltinsAssembler::IntPtrZero() { 451cb0ef41Sopenharmony_ci return IntPtrConstant(0); 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci// If code is a builtin, return the address to the (possibly embedded) builtin 491cb0ef41Sopenharmony_ci// code entry, otherwise return the entry of the code object itself. 501cb0ef41Sopenharmony_ciTNode<RawPtrT> RegExpBuiltinsAssembler::LoadCodeObjectEntry(TNode<CodeT> code) { 511cb0ef41Sopenharmony_ci if (V8_EXTERNAL_CODE_SPACE_BOOL) { 521cb0ef41Sopenharmony_ci // When external code space is enabled we can load the entry point directly 531cb0ef41Sopenharmony_ci // from the CodeT object. 541cb0ef41Sopenharmony_ci return GetCodeEntry(code); 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci TVARIABLE(RawPtrT, var_result); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci Label if_code_is_off_heap(this), out(this); 601cb0ef41Sopenharmony_ci TNode<Int32T> builtin_index = 611cb0ef41Sopenharmony_ci LoadObjectField<Int32T>(code, Code::kBuiltinIndexOffset); 621cb0ef41Sopenharmony_ci { 631cb0ef41Sopenharmony_ci GotoIfNot( 641cb0ef41Sopenharmony_ci Word32Equal(builtin_index, 651cb0ef41Sopenharmony_ci Int32Constant(static_cast<int>(Builtin::kNoBuiltinId))), 661cb0ef41Sopenharmony_ci &if_code_is_off_heap); 671cb0ef41Sopenharmony_ci var_result = ReinterpretCast<RawPtrT>( 681cb0ef41Sopenharmony_ci IntPtrAdd(BitcastTaggedToWord(code), 691cb0ef41Sopenharmony_ci IntPtrConstant(Code::kHeaderSize - kHeapObjectTag))); 701cb0ef41Sopenharmony_ci Goto(&out); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci BIND(&if_code_is_off_heap); 741cb0ef41Sopenharmony_ci { 751cb0ef41Sopenharmony_ci TNode<IntPtrT> builtin_entry_offset_from_isolate_root = 761cb0ef41Sopenharmony_ci IntPtrAdd(IntPtrConstant(IsolateData::builtin_entry_table_offset()), 771cb0ef41Sopenharmony_ci ChangeInt32ToIntPtr(Word32Shl( 781cb0ef41Sopenharmony_ci builtin_index, Int32Constant(kSystemPointerSizeLog2)))); 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci var_result = ReinterpretCast<RawPtrT>( 811cb0ef41Sopenharmony_ci Load(MachineType::Pointer(), 821cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::isolate_root(isolate())), 831cb0ef41Sopenharmony_ci builtin_entry_offset_from_isolate_root)); 841cb0ef41Sopenharmony_ci Goto(&out); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci BIND(&out); 881cb0ef41Sopenharmony_ci return var_result.value(); 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------- 921cb0ef41Sopenharmony_ci// ES6 section 21.2 RegExp Objects 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ciTNode<JSRegExpResult> RegExpBuiltinsAssembler::AllocateRegExpResult( 951cb0ef41Sopenharmony_ci TNode<Context> context, TNode<Smi> length, TNode<Smi> index, 961cb0ef41Sopenharmony_ci TNode<String> input, TNode<JSRegExp> regexp, TNode<Number> last_index, 971cb0ef41Sopenharmony_ci TNode<BoolT> has_indices, TNode<FixedArray>* elements_out) { 981cb0ef41Sopenharmony_ci CSA_DCHECK(this, SmiLessThanOrEqual( 991cb0ef41Sopenharmony_ci length, SmiConstant(JSArray::kMaxFastArrayLength))); 1001cb0ef41Sopenharmony_ci CSA_DCHECK(this, SmiGreaterThan(length, SmiConstant(0))); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Allocate. 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci Label result_has_indices(this), allocated(this); 1051cb0ef41Sopenharmony_ci const ElementsKind elements_kind = PACKED_ELEMENTS; 1061cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> no_gc_site = base::nullopt; 1071cb0ef41Sopenharmony_ci TNode<IntPtrT> length_intptr = SmiUntag(length); 1081cb0ef41Sopenharmony_ci // Note: The returned `var_elements` may be in young large object space, but 1091cb0ef41Sopenharmony_ci // `var_array` is guaranteed to be in new space so we could skip write 1101cb0ef41Sopenharmony_ci // barriers below. 1111cb0ef41Sopenharmony_ci TVARIABLE(JSArray, var_array); 1121cb0ef41Sopenharmony_ci TVARIABLE(FixedArrayBase, var_elements); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci GotoIf(has_indices, &result_has_indices); 1151cb0ef41Sopenharmony_ci { 1161cb0ef41Sopenharmony_ci TNode<Map> map = CAST(LoadContextElement(LoadNativeContext(context), 1171cb0ef41Sopenharmony_ci Context::REGEXP_RESULT_MAP_INDEX)); 1181cb0ef41Sopenharmony_ci std::tie(var_array, var_elements) = 1191cb0ef41Sopenharmony_ci AllocateUninitializedJSArrayWithElements( 1201cb0ef41Sopenharmony_ci elements_kind, map, length, no_gc_site, length_intptr, 1211cb0ef41Sopenharmony_ci AllocationFlag::kAllowLargeObjectAllocation, JSRegExpResult::kSize); 1221cb0ef41Sopenharmony_ci Goto(&allocated); 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci BIND(&result_has_indices); 1261cb0ef41Sopenharmony_ci { 1271cb0ef41Sopenharmony_ci TNode<Map> map = 1281cb0ef41Sopenharmony_ci CAST(LoadContextElement(LoadNativeContext(context), 1291cb0ef41Sopenharmony_ci Context::REGEXP_RESULT_WITH_INDICES_MAP_INDEX)); 1301cb0ef41Sopenharmony_ci std::tie(var_array, var_elements) = 1311cb0ef41Sopenharmony_ci AllocateUninitializedJSArrayWithElements( 1321cb0ef41Sopenharmony_ci elements_kind, map, length, no_gc_site, length_intptr, 1331cb0ef41Sopenharmony_ci AllocationFlag::kAllowLargeObjectAllocation, 1341cb0ef41Sopenharmony_ci JSRegExpResultWithIndices::kSize); 1351cb0ef41Sopenharmony_ci Goto(&allocated); 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci BIND(&allocated); 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci // Finish result initialization. 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci TNode<JSRegExpResult> result = 1431cb0ef41Sopenharmony_ci UncheckedCast<JSRegExpResult>(var_array.value()); 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci // Load undefined value once here to avoid multiple LoadRoots. 1461cb0ef41Sopenharmony_ci TNode<Oddball> undefined_value = UncheckedCast<Oddball>( 1471cb0ef41Sopenharmony_ci CodeAssembler::LoadRoot(RootIndex::kUndefinedValue)); 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(result, JSRegExpResult::kIndexOffset, index); 1501cb0ef41Sopenharmony_ci // TODO(jgruber,turbofan): Could skip barrier but the MemoryOptimizer 1511cb0ef41Sopenharmony_ci // complains. 1521cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResult::kInputOffset, input); 1531cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(result, JSRegExpResult::kGroupsOffset, 1541cb0ef41Sopenharmony_ci undefined_value); 1551cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(result, JSRegExpResult::kNamesOffset, 1561cb0ef41Sopenharmony_ci undefined_value); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResult::kRegexpInputOffset, input); 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci // If non-smi last_index then store an SmiZero instead. 1611cb0ef41Sopenharmony_ci { 1621cb0ef41Sopenharmony_ci TNode<Smi> last_index_smi = Select<Smi>( 1631cb0ef41Sopenharmony_ci TaggedIsSmi(last_index), [=] { return CAST(last_index); }, 1641cb0ef41Sopenharmony_ci [=] { return SmiZero(); }); 1651cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResult::kRegexpLastIndexOffset, 1661cb0ef41Sopenharmony_ci last_index_smi); 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci Label finish_initialization(this); 1701cb0ef41Sopenharmony_ci GotoIfNot(has_indices, &finish_initialization); 1711cb0ef41Sopenharmony_ci { 1721cb0ef41Sopenharmony_ci static_assert( 1731cb0ef41Sopenharmony_ci std::is_base_of<JSRegExpResult, JSRegExpResultWithIndices>::value, 1741cb0ef41Sopenharmony_ci "JSRegExpResultWithIndices is a subclass of JSRegExpResult"); 1751cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 1761cb0ef41Sopenharmony_ci result, JSRegExpResultWithIndices::kIndicesOffset, undefined_value); 1771cb0ef41Sopenharmony_ci Goto(&finish_initialization); 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci BIND(&finish_initialization); 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci // Finish elements initialization. 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci FillFixedArrayWithValue(elements_kind, var_elements.value(), IntPtrZero(), 1851cb0ef41Sopenharmony_ci length_intptr, RootIndex::kUndefinedValue); 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci if (elements_out) *elements_out = CAST(var_elements.value()); 1881cb0ef41Sopenharmony_ci return result; 1891cb0ef41Sopenharmony_ci} 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ciTNode<Object> RegExpBuiltinsAssembler::FastLoadLastIndexBeforeSmiCheck( 1921cb0ef41Sopenharmony_ci TNode<JSRegExp> regexp) { 1931cb0ef41Sopenharmony_ci // Load the in-object field. 1941cb0ef41Sopenharmony_ci static const int field_offset = 1951cb0ef41Sopenharmony_ci JSRegExp::kHeaderSize + JSRegExp::kLastIndexFieldIndex * kTaggedSize; 1961cb0ef41Sopenharmony_ci return LoadObjectField(regexp, field_offset); 1971cb0ef41Sopenharmony_ci} 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ciTNode<Object> RegExpBuiltinsAssembler::SlowLoadLastIndex(TNode<Context> context, 2001cb0ef41Sopenharmony_ci TNode<Object> regexp) { 2011cb0ef41Sopenharmony_ci return GetProperty(context, regexp, isolate()->factory()->lastIndex_string()); 2021cb0ef41Sopenharmony_ci} 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci// The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified 2051cb0ef41Sopenharmony_ci// JSRegExp instance. 2061cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::FastStoreLastIndex(TNode<JSRegExp> regexp, 2071cb0ef41Sopenharmony_ci TNode<Smi> value) { 2081cb0ef41Sopenharmony_ci // Store the in-object field. 2091cb0ef41Sopenharmony_ci static const int field_offset = 2101cb0ef41Sopenharmony_ci JSRegExp::kHeaderSize + JSRegExp::kLastIndexFieldIndex * kTaggedSize; 2111cb0ef41Sopenharmony_ci StoreObjectField(regexp, field_offset, value); 2121cb0ef41Sopenharmony_ci} 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::SlowStoreLastIndex(TNode<Context> context, 2151cb0ef41Sopenharmony_ci TNode<Object> regexp, 2161cb0ef41Sopenharmony_ci TNode<Object> value) { 2171cb0ef41Sopenharmony_ci TNode<String> name = HeapConstant(isolate()->factory()->lastIndex_string()); 2181cb0ef41Sopenharmony_ci SetPropertyStrict(context, regexp, name, value); 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ciTNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( 2221cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSRegExp> regexp, 2231cb0ef41Sopenharmony_ci TNode<RegExpMatchInfo> match_info, TNode<String> string, 2241cb0ef41Sopenharmony_ci TNode<Number> last_index) { 2251cb0ef41Sopenharmony_ci Label named_captures(this), maybe_build_indices(this), out(this); 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci TNode<IntPtrT> num_indices = SmiUntag(CAST(UnsafeLoadFixedArrayElement( 2281cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kNumberOfCapturesIndex))); 2291cb0ef41Sopenharmony_ci TNode<Smi> num_results = SmiTag(WordShr(num_indices, 1)); 2301cb0ef41Sopenharmony_ci TNode<Smi> start = CAST(UnsafeLoadFixedArrayElement( 2311cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kFirstCaptureIndex)); 2321cb0ef41Sopenharmony_ci TNode<Smi> end = CAST(UnsafeLoadFixedArrayElement( 2331cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kFirstCaptureIndex + 1)); 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci // Calculate the substring of the first match before creating the result array 2361cb0ef41Sopenharmony_ci // to avoid an unnecessary write barrier storing the first result. 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci TNode<String> first = 2391cb0ef41Sopenharmony_ci CAST(CallBuiltin(Builtin::kSubString, context, string, start, end)); 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci // Load flags and check if the result object needs to have indices. 2421cb0ef41Sopenharmony_ci const TNode<Smi> flags = 2431cb0ef41Sopenharmony_ci CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset)); 2441cb0ef41Sopenharmony_ci const TNode<BoolT> has_indices = IsSetSmi(flags, JSRegExp::kHasIndices); 2451cb0ef41Sopenharmony_ci TNode<FixedArray> result_elements; 2461cb0ef41Sopenharmony_ci TNode<JSRegExpResult> result = 2471cb0ef41Sopenharmony_ci AllocateRegExpResult(context, num_results, start, string, regexp, 2481cb0ef41Sopenharmony_ci last_index, has_indices, &result_elements); 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(result_elements, 0, first); 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci // If no captures exist we can skip named capture handling as well. 2531cb0ef41Sopenharmony_ci GotoIf(SmiEqual(num_results, SmiConstant(1)), &maybe_build_indices); 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // Store all remaining captures. 2561cb0ef41Sopenharmony_ci TNode<IntPtrT> limit = IntPtrAdd( 2571cb0ef41Sopenharmony_ci IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_from_cursor, 2601cb0ef41Sopenharmony_ci IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); 2611cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_to_cursor, IntPtrConstant(1)); 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci Label loop(this, {&var_from_cursor, &var_to_cursor}); 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci Goto(&loop); 2661cb0ef41Sopenharmony_ci BIND(&loop); 2671cb0ef41Sopenharmony_ci { 2681cb0ef41Sopenharmony_ci TNode<IntPtrT> from_cursor = var_from_cursor.value(); 2691cb0ef41Sopenharmony_ci TNode<IntPtrT> to_cursor = var_to_cursor.value(); 2701cb0ef41Sopenharmony_ci TNode<Smi> start_cursor = 2711cb0ef41Sopenharmony_ci CAST(UnsafeLoadFixedArrayElement(match_info, from_cursor)); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci Label next_iter(this); 2741cb0ef41Sopenharmony_ci GotoIf(SmiEqual(start_cursor, SmiConstant(-1)), &next_iter); 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci TNode<IntPtrT> from_cursor_plus1 = 2771cb0ef41Sopenharmony_ci IntPtrAdd(from_cursor, IntPtrConstant(1)); 2781cb0ef41Sopenharmony_ci TNode<Smi> end_cursor = 2791cb0ef41Sopenharmony_ci CAST(UnsafeLoadFixedArrayElement(match_info, from_cursor_plus1)); 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci TNode<String> capture = CAST(CallBuiltin(Builtin::kSubString, context, 2821cb0ef41Sopenharmony_ci string, start_cursor, end_cursor)); 2831cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(result_elements, to_cursor, capture); 2841cb0ef41Sopenharmony_ci Goto(&next_iter); 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci BIND(&next_iter); 2871cb0ef41Sopenharmony_ci var_from_cursor = IntPtrAdd(from_cursor, IntPtrConstant(2)); 2881cb0ef41Sopenharmony_ci var_to_cursor = IntPtrAdd(to_cursor, IntPtrConstant(1)); 2891cb0ef41Sopenharmony_ci Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, 2901cb0ef41Sopenharmony_ci &named_captures); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci BIND(&named_captures); 2941cb0ef41Sopenharmony_ci { 2951cb0ef41Sopenharmony_ci CSA_DCHECK(this, SmiGreaterThan(num_results, SmiConstant(1))); 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci // Preparations for named capture properties. Exit early if the result does 2981cb0ef41Sopenharmony_ci // not have any named captures to minimize performance impact. 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci TNode<FixedArray> data = 3011cb0ef41Sopenharmony_ci CAST(LoadObjectField(regexp, JSRegExp::kDataOffset)); 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci // We reach this point only if captures exist, implying that the assigned 3041cb0ef41Sopenharmony_ci // regexp engine must be able to handle captures. 3051cb0ef41Sopenharmony_ci CSA_DCHECK( 3061cb0ef41Sopenharmony_ci this, 3071cb0ef41Sopenharmony_ci Word32Or( 3081cb0ef41Sopenharmony_ci SmiEqual(CAST(LoadFixedArrayElement(data, JSRegExp::kTagIndex)), 3091cb0ef41Sopenharmony_ci SmiConstant(JSRegExp::IRREGEXP)), 3101cb0ef41Sopenharmony_ci SmiEqual(CAST(LoadFixedArrayElement(data, JSRegExp::kTagIndex)), 3111cb0ef41Sopenharmony_ci SmiConstant(JSRegExp::EXPERIMENTAL)))); 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci // The names fixed array associates names at even indices with a capture 3141cb0ef41Sopenharmony_ci // index at odd indices. 3151cb0ef41Sopenharmony_ci TNode<Object> maybe_names = 3161cb0ef41Sopenharmony_ci LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureNameMapIndex); 3171cb0ef41Sopenharmony_ci GotoIf(TaggedEqual(maybe_names, SmiZero()), &maybe_build_indices); 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci // One or more named captures exist, add a property for each one. 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci TNode<FixedArray> names = CAST(maybe_names); 3221cb0ef41Sopenharmony_ci TNode<IntPtrT> names_length = LoadAndUntagFixedArrayBaseLength(names); 3231cb0ef41Sopenharmony_ci CSA_DCHECK(this, IntPtrGreaterThan(names_length, IntPtrZero())); 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci // Stash names in case we need them to build the indices array later. 3261cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResult::kNamesOffset, names); 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci // Allocate a new object to store the named capture properties. 3291cb0ef41Sopenharmony_ci // TODO(jgruber): Could be optimized by adding the object map to the heap 3301cb0ef41Sopenharmony_ci // root list. 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci TNode<IntPtrT> num_properties = WordSar(names_length, 1); 3331cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(context); 3341cb0ef41Sopenharmony_ci TNode<Map> map = LoadSlowObjectWithNullPrototypeMap(native_context); 3351cb0ef41Sopenharmony_ci TNode<HeapObject> properties; 3361cb0ef41Sopenharmony_ci if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 3371cb0ef41Sopenharmony_ci properties = AllocateSwissNameDictionary(num_properties); 3381cb0ef41Sopenharmony_ci } else { 3391cb0ef41Sopenharmony_ci properties = AllocateNameDictionary( 3401cb0ef41Sopenharmony_ci num_properties, AllocationFlag::kAllowLargeObjectAllocation); 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci TNode<JSObject> group_object = AllocateJSObjectFromMap(map, properties); 3441cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResult::kGroupsOffset, group_object); 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_i, IntPtrZero()); 3471cb0ef41Sopenharmony_ci 3481cb0ef41Sopenharmony_ci Label inner_loop(this, &var_i); 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci Goto(&inner_loop); 3511cb0ef41Sopenharmony_ci BIND(&inner_loop); 3521cb0ef41Sopenharmony_ci { 3531cb0ef41Sopenharmony_ci TNode<IntPtrT> i = var_i.value(); 3541cb0ef41Sopenharmony_ci TNode<IntPtrT> i_plus_1 = IntPtrAdd(i, IntPtrConstant(1)); 3551cb0ef41Sopenharmony_ci TNode<IntPtrT> i_plus_2 = IntPtrAdd(i_plus_1, IntPtrConstant(1)); 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci TNode<String> name = CAST(LoadFixedArrayElement(names, i)); 3581cb0ef41Sopenharmony_ci TNode<Smi> index = CAST(LoadFixedArrayElement(names, i_plus_1)); 3591cb0ef41Sopenharmony_ci TNode<HeapObject> capture = 3601cb0ef41Sopenharmony_ci CAST(LoadFixedArrayElement(result_elements, SmiUntag(index))); 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci // TODO(v8:8213): For maintainability, we should call a CSA/Torque 3631cb0ef41Sopenharmony_ci // implementation of CreateDataProperty instead. 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci // At this point the spec says to call CreateDataProperty. However, we can 3661cb0ef41Sopenharmony_ci // skip most of the steps and go straight to adding a dictionary entry 3671cb0ef41Sopenharmony_ci // because we know a bunch of useful facts: 3681cb0ef41Sopenharmony_ci // - All keys are non-numeric internalized strings 3691cb0ef41Sopenharmony_ci // - No keys repeat 3701cb0ef41Sopenharmony_ci // - Receiver has no prototype 3711cb0ef41Sopenharmony_ci // - Receiver isn't used as a prototype 3721cb0ef41Sopenharmony_ci // - Receiver isn't any special object like a Promise intrinsic object 3731cb0ef41Sopenharmony_ci // - Receiver is extensible 3741cb0ef41Sopenharmony_ci // - Receiver has no interceptors 3751cb0ef41Sopenharmony_ci Label add_dictionary_property_slow(this, Label::kDeferred); 3761cb0ef41Sopenharmony_ci Add<PropertyDictionary>(CAST(properties), name, capture, 3771cb0ef41Sopenharmony_ci &add_dictionary_property_slow); 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci var_i = i_plus_2; 3801cb0ef41Sopenharmony_ci Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), 3811cb0ef41Sopenharmony_ci &maybe_build_indices, &inner_loop); 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci BIND(&add_dictionary_property_slow); 3841cb0ef41Sopenharmony_ci // If the dictionary needs resizing, the above Add call will jump here 3851cb0ef41Sopenharmony_ci // before making any changes. This shouldn't happen because we allocated 3861cb0ef41Sopenharmony_ci // the dictionary with enough space above. 3871cb0ef41Sopenharmony_ci Unreachable(); 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci } 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci // Build indices if needed (i.e. if the /d flag is present) after named 3921cb0ef41Sopenharmony_ci // capture groups are processed. 3931cb0ef41Sopenharmony_ci BIND(&maybe_build_indices); 3941cb0ef41Sopenharmony_ci GotoIfNot(has_indices, &out); 3951cb0ef41Sopenharmony_ci { 3961cb0ef41Sopenharmony_ci const TNode<Object> maybe_names = 3971cb0ef41Sopenharmony_ci LoadObjectField(result, JSRegExpResultWithIndices::kNamesOffset); 3981cb0ef41Sopenharmony_ci const TNode<JSRegExpResultIndices> indices = 3991cb0ef41Sopenharmony_ci UncheckedCast<JSRegExpResultIndices>( 4001cb0ef41Sopenharmony_ci CallRuntime(Runtime::kRegExpBuildIndices, context, regexp, 4011cb0ef41Sopenharmony_ci match_info, maybe_names)); 4021cb0ef41Sopenharmony_ci StoreObjectField(result, JSRegExpResultWithIndices::kIndicesOffset, 4031cb0ef41Sopenharmony_ci indices); 4041cb0ef41Sopenharmony_ci Goto(&out); 4051cb0ef41Sopenharmony_ci } 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ci BIND(&out); 4081cb0ef41Sopenharmony_ci return result; 4091cb0ef41Sopenharmony_ci} 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::GetStringPointers( 4121cb0ef41Sopenharmony_ci TNode<RawPtrT> string_data, TNode<IntPtrT> offset, 4131cb0ef41Sopenharmony_ci TNode<IntPtrT> last_index, TNode<IntPtrT> string_length, 4141cb0ef41Sopenharmony_ci String::Encoding encoding, TVariable<RawPtrT>* var_string_start, 4151cb0ef41Sopenharmony_ci TVariable<RawPtrT>* var_string_end) { 4161cb0ef41Sopenharmony_ci DCHECK_EQ(var_string_start->rep(), MachineType::PointerRepresentation()); 4171cb0ef41Sopenharmony_ci DCHECK_EQ(var_string_end->rep(), MachineType::PointerRepresentation()); 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci const ElementsKind kind = (encoding == String::ONE_BYTE_ENCODING) 4201cb0ef41Sopenharmony_ci ? UINT8_ELEMENTS 4211cb0ef41Sopenharmony_ci : UINT16_ELEMENTS; 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci TNode<IntPtrT> from_offset = 4241cb0ef41Sopenharmony_ci ElementOffsetFromIndex(IntPtrAdd(offset, last_index), kind); 4251cb0ef41Sopenharmony_ci *var_string_start = 4261cb0ef41Sopenharmony_ci ReinterpretCast<RawPtrT>(IntPtrAdd(string_data, from_offset)); 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci TNode<IntPtrT> to_offset = 4291cb0ef41Sopenharmony_ci ElementOffsetFromIndex(IntPtrAdd(offset, string_length), kind); 4301cb0ef41Sopenharmony_ci *var_string_end = ReinterpretCast<RawPtrT>(IntPtrAdd(string_data, to_offset)); 4311cb0ef41Sopenharmony_ci} 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ciTNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal( 4341cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string, 4351cb0ef41Sopenharmony_ci TNode<Number> last_index, TNode<RegExpMatchInfo> match_info, 4361cb0ef41Sopenharmony_ci RegExp::ExecQuirks exec_quirks) { 4371cb0ef41Sopenharmony_ci ToDirectStringAssembler to_direct(state(), string); 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci TVARIABLE(HeapObject, var_result); 4401cb0ef41Sopenharmony_ci Label out(this), atom(this), runtime(this, Label::kDeferred), 4411cb0ef41Sopenharmony_ci retry_experimental(this, Label::kDeferred); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci // External constants. 4441cb0ef41Sopenharmony_ci TNode<ExternalReference> isolate_address = 4451cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::isolate_address(isolate())); 4461cb0ef41Sopenharmony_ci TNode<ExternalReference> static_offsets_vector_address = ExternalConstant( 4471cb0ef41Sopenharmony_ci ExternalReference::address_of_static_offsets_vector(isolate())); 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci // At this point, last_index is definitely a canonicalized non-negative 4501cb0ef41Sopenharmony_ci // number, which implies that any non-Smi last_index is greater than 4511cb0ef41Sopenharmony_ci // the maximal string length. If lastIndex > string.length then the matcher 4521cb0ef41Sopenharmony_ci // must fail. 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci Label if_failure(this); 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberNormalized(last_index)); 4571cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberPositive(last_index)); 4581cb0ef41Sopenharmony_ci GotoIf(TaggedIsNotSmi(last_index), &if_failure); 4591cb0ef41Sopenharmony_ci 4601cb0ef41Sopenharmony_ci TNode<IntPtrT> int_string_length = LoadStringLengthAsWord(string); 4611cb0ef41Sopenharmony_ci TNode<IntPtrT> int_last_index = SmiUntag(CAST(last_index)); 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci GotoIf(UintPtrGreaterThan(int_last_index, int_string_length), &if_failure); 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ci // Since the RegExp has been compiled, data contains a fixed array. 4661cb0ef41Sopenharmony_ci TNode<FixedArray> data = CAST(LoadObjectField(regexp, JSRegExp::kDataOffset)); 4671cb0ef41Sopenharmony_ci { 4681cb0ef41Sopenharmony_ci // Dispatch on the type of the RegExp. 4691cb0ef41Sopenharmony_ci { 4701cb0ef41Sopenharmony_ci Label next(this), unreachable(this, Label::kDeferred); 4711cb0ef41Sopenharmony_ci TNode<Int32T> tag = LoadAndUntagToWord32FixedArrayElement( 4721cb0ef41Sopenharmony_ci data, IntPtrConstant(JSRegExp::kTagIndex)); 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci int32_t values[] = { 4751cb0ef41Sopenharmony_ci JSRegExp::IRREGEXP, 4761cb0ef41Sopenharmony_ci JSRegExp::ATOM, 4771cb0ef41Sopenharmony_ci JSRegExp::EXPERIMENTAL, 4781cb0ef41Sopenharmony_ci }; 4791cb0ef41Sopenharmony_ci Label* labels[] = {&next, &atom, &next}; 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci STATIC_ASSERT(arraysize(values) == arraysize(labels)); 4821cb0ef41Sopenharmony_ci Switch(tag, &unreachable, values, labels, arraysize(values)); 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ci BIND(&unreachable); 4851cb0ef41Sopenharmony_ci Unreachable(); 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ci BIND(&next); 4881cb0ef41Sopenharmony_ci } 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci // Check (number_of_captures + 1) * 2 <= offsets vector size 4911cb0ef41Sopenharmony_ci // Or number_of_captures <= offsets vector size / 2 - 1 4921cb0ef41Sopenharmony_ci TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement( 4931cb0ef41Sopenharmony_ci data, JSRegExp::kIrregexpCaptureCountIndex)); 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci const int kOffsetsSize = Isolate::kJSRegexpStaticOffsetsVectorSize; 4961cb0ef41Sopenharmony_ci STATIC_ASSERT(kOffsetsSize >= 2); 4971cb0ef41Sopenharmony_ci GotoIf(SmiAbove(capture_count, SmiConstant(kOffsetsSize / 2 - 1)), 4981cb0ef41Sopenharmony_ci &runtime); 4991cb0ef41Sopenharmony_ci } 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_ci // Unpack the string if possible. 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci to_direct.TryToDirect(&runtime); 5041cb0ef41Sopenharmony_ci 5051cb0ef41Sopenharmony_ci // Load the irregexp code or bytecode object and offsets into the subject 5061cb0ef41Sopenharmony_ci // string. Both depend on whether the string is one- or two-byte. 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci TVARIABLE(RawPtrT, var_string_start); 5091cb0ef41Sopenharmony_ci TVARIABLE(RawPtrT, var_string_end); 5101cb0ef41Sopenharmony_ci TVARIABLE(Object, var_code); 5111cb0ef41Sopenharmony_ci TVARIABLE(Object, var_bytecode); 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_ci { 5141cb0ef41Sopenharmony_ci TNode<RawPtrT> direct_string_data = to_direct.PointerToData(&runtime); 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ci Label next(this), if_isonebyte(this), if_istwobyte(this, Label::kDeferred); 5171cb0ef41Sopenharmony_ci Branch(IsOneByteStringInstanceType(to_direct.instance_type()), 5181cb0ef41Sopenharmony_ci &if_isonebyte, &if_istwobyte); 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci BIND(&if_isonebyte); 5211cb0ef41Sopenharmony_ci { 5221cb0ef41Sopenharmony_ci GetStringPointers(direct_string_data, to_direct.offset(), int_last_index, 5231cb0ef41Sopenharmony_ci int_string_length, String::ONE_BYTE_ENCODING, 5241cb0ef41Sopenharmony_ci &var_string_start, &var_string_end); 5251cb0ef41Sopenharmony_ci var_code = 5261cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpLatin1CodeIndex); 5271cb0ef41Sopenharmony_ci var_bytecode = UnsafeLoadFixedArrayElement( 5281cb0ef41Sopenharmony_ci data, JSRegExp::kIrregexpLatin1BytecodeIndex); 5291cb0ef41Sopenharmony_ci Goto(&next); 5301cb0ef41Sopenharmony_ci } 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ci BIND(&if_istwobyte); 5331cb0ef41Sopenharmony_ci { 5341cb0ef41Sopenharmony_ci GetStringPointers(direct_string_data, to_direct.offset(), int_last_index, 5351cb0ef41Sopenharmony_ci int_string_length, String::TWO_BYTE_ENCODING, 5361cb0ef41Sopenharmony_ci &var_string_start, &var_string_end); 5371cb0ef41Sopenharmony_ci var_code = 5381cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpUC16CodeIndex); 5391cb0ef41Sopenharmony_ci var_bytecode = UnsafeLoadFixedArrayElement( 5401cb0ef41Sopenharmony_ci data, JSRegExp::kIrregexpUC16BytecodeIndex); 5411cb0ef41Sopenharmony_ci Goto(&next); 5421cb0ef41Sopenharmony_ci } 5431cb0ef41Sopenharmony_ci 5441cb0ef41Sopenharmony_ci BIND(&next); 5451cb0ef41Sopenharmony_ci } 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_ci // Check that the irregexp code has been generated for the actual string 5481cb0ef41Sopenharmony_ci // encoding. If it has, the field contains a code object; and otherwise it 5491cb0ef41Sopenharmony_ci // contains the uninitialized sentinel as a smi. 5501cb0ef41Sopenharmony_ci#ifdef DEBUG 5511cb0ef41Sopenharmony_ci { 5521cb0ef41Sopenharmony_ci Label next(this); 5531cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsSmi(var_code.value()), &next); 5541cb0ef41Sopenharmony_ci CSA_DCHECK(this, SmiEqual(CAST(var_code.value()), 5551cb0ef41Sopenharmony_ci SmiConstant(JSRegExp::kUninitializedValue))); 5561cb0ef41Sopenharmony_ci Goto(&next); 5571cb0ef41Sopenharmony_ci BIND(&next); 5581cb0ef41Sopenharmony_ci } 5591cb0ef41Sopenharmony_ci#endif 5601cb0ef41Sopenharmony_ci 5611cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(var_code.value()), &runtime); 5621cb0ef41Sopenharmony_ci TNode<CodeT> code = CAST(var_code.value()); 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci Label if_success(this), if_exception(this, Label::kDeferred); 5651cb0ef41Sopenharmony_ci { 5661cb0ef41Sopenharmony_ci IncrementCounter(isolate()->counters()->regexp_entry_native(), 1); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci // Set up args for the final call into generated Irregexp code. 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci MachineType type_int32 = MachineType::Int32(); 5711cb0ef41Sopenharmony_ci MachineType type_tagged = MachineType::AnyTagged(); 5721cb0ef41Sopenharmony_ci MachineType type_ptr = MachineType::Pointer(); 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci // Result: A NativeRegExpMacroAssembler::Result return code. 5751cb0ef41Sopenharmony_ci MachineType retval_type = type_int32; 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci // Argument 0: Original subject string. 5781cb0ef41Sopenharmony_ci MachineType arg0_type = type_tagged; 5791cb0ef41Sopenharmony_ci TNode<String> arg0 = string; 5801cb0ef41Sopenharmony_ci 5811cb0ef41Sopenharmony_ci // Argument 1: Previous index. 5821cb0ef41Sopenharmony_ci MachineType arg1_type = type_int32; 5831cb0ef41Sopenharmony_ci TNode<Int32T> arg1 = TruncateIntPtrToInt32(int_last_index); 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci // Argument 2: Start of string data. This argument is ignored in the 5861cb0ef41Sopenharmony_ci // interpreter. 5871cb0ef41Sopenharmony_ci MachineType arg2_type = type_ptr; 5881cb0ef41Sopenharmony_ci TNode<RawPtrT> arg2 = var_string_start.value(); 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_ci // Argument 3: End of string data. This argument is ignored in the 5911cb0ef41Sopenharmony_ci // interpreter. 5921cb0ef41Sopenharmony_ci MachineType arg3_type = type_ptr; 5931cb0ef41Sopenharmony_ci TNode<RawPtrT> arg3 = var_string_end.value(); 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_ci // Argument 4: static offsets vector buffer. 5961cb0ef41Sopenharmony_ci MachineType arg4_type = type_ptr; 5971cb0ef41Sopenharmony_ci TNode<ExternalReference> arg4 = static_offsets_vector_address; 5981cb0ef41Sopenharmony_ci 5991cb0ef41Sopenharmony_ci // Argument 5: Number of capture registers. 6001cb0ef41Sopenharmony_ci // Setting this to the number of registers required to store all captures 6011cb0ef41Sopenharmony_ci // forces global regexps to behave as non-global. 6021cb0ef41Sopenharmony_ci TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement( 6031cb0ef41Sopenharmony_ci data, JSRegExp::kIrregexpCaptureCountIndex)); 6041cb0ef41Sopenharmony_ci // capture_count is the number of captures without the match itself. 6051cb0ef41Sopenharmony_ci // Required registers = (capture_count + 1) * 2. 6061cb0ef41Sopenharmony_ci STATIC_ASSERT(Internals::IsValidSmi((JSRegExp::kMaxCaptures + 1) * 2)); 6071cb0ef41Sopenharmony_ci TNode<Smi> register_count = 6081cb0ef41Sopenharmony_ci SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1); 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ci MachineType arg5_type = type_int32; 6111cb0ef41Sopenharmony_ci TNode<Int32T> arg5 = SmiToInt32(register_count); 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci // Argument 6: Indicate that this is a direct call from JavaScript. 6141cb0ef41Sopenharmony_ci MachineType arg6_type = type_int32; 6151cb0ef41Sopenharmony_ci TNode<Int32T> arg6 = Int32Constant(RegExp::CallOrigin::kFromJs); 6161cb0ef41Sopenharmony_ci 6171cb0ef41Sopenharmony_ci // Argument 7: Pass current isolate address. 6181cb0ef41Sopenharmony_ci MachineType arg7_type = type_ptr; 6191cb0ef41Sopenharmony_ci TNode<ExternalReference> arg7 = isolate_address; 6201cb0ef41Sopenharmony_ci 6211cb0ef41Sopenharmony_ci // Argument 8: Regular expression object. This argument is ignored in native 6221cb0ef41Sopenharmony_ci // irregexp code. 6231cb0ef41Sopenharmony_ci MachineType arg8_type = type_tagged; 6241cb0ef41Sopenharmony_ci TNode<JSRegExp> arg8 = regexp; 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci TNode<RawPtrT> code_entry = LoadCodeObjectEntry(code); 6271cb0ef41Sopenharmony_ci 6281cb0ef41Sopenharmony_ci // AIX uses function descriptors on CFunction calls. code_entry in this case 6291cb0ef41Sopenharmony_ci // may also point to a Regex interpreter entry trampoline which does not 6301cb0ef41Sopenharmony_ci // have a function descriptor. This method is ineffective on other platforms 6311cb0ef41Sopenharmony_ci // and is equivalent to CallCFunction. 6321cb0ef41Sopenharmony_ci TNode<Int32T> result = 6331cb0ef41Sopenharmony_ci UncheckedCast<Int32T>(CallCFunctionWithoutFunctionDescriptor( 6341cb0ef41Sopenharmony_ci code_entry, retval_type, std::make_pair(arg0_type, arg0), 6351cb0ef41Sopenharmony_ci std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2), 6361cb0ef41Sopenharmony_ci std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4), 6371cb0ef41Sopenharmony_ci std::make_pair(arg5_type, arg5), std::make_pair(arg6_type, arg6), 6381cb0ef41Sopenharmony_ci std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8))); 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ci // Check the result. 6411cb0ef41Sopenharmony_ci // We expect exactly one result since we force the called regexp to behave 6421cb0ef41Sopenharmony_ci // as non-global. 6431cb0ef41Sopenharmony_ci TNode<IntPtrT> int_result = ChangeInt32ToIntPtr(result); 6441cb0ef41Sopenharmony_ci GotoIf( 6451cb0ef41Sopenharmony_ci IntPtrEqual(int_result, IntPtrConstant(RegExp::kInternalRegExpSuccess)), 6461cb0ef41Sopenharmony_ci &if_success); 6471cb0ef41Sopenharmony_ci GotoIf( 6481cb0ef41Sopenharmony_ci IntPtrEqual(int_result, IntPtrConstant(RegExp::kInternalRegExpFailure)), 6491cb0ef41Sopenharmony_ci &if_failure); 6501cb0ef41Sopenharmony_ci GotoIf(IntPtrEqual(int_result, 6511cb0ef41Sopenharmony_ci IntPtrConstant(RegExp::kInternalRegExpException)), 6521cb0ef41Sopenharmony_ci &if_exception); 6531cb0ef41Sopenharmony_ci GotoIf(IntPtrEqual( 6541cb0ef41Sopenharmony_ci int_result, 6551cb0ef41Sopenharmony_ci IntPtrConstant(RegExp::kInternalRegExpFallbackToExperimental)), 6561cb0ef41Sopenharmony_ci &retry_experimental); 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci CSA_DCHECK(this, IntPtrEqual(int_result, 6591cb0ef41Sopenharmony_ci IntPtrConstant(RegExp::kInternalRegExpRetry))); 6601cb0ef41Sopenharmony_ci Goto(&runtime); 6611cb0ef41Sopenharmony_ci } 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci BIND(&if_success); 6641cb0ef41Sopenharmony_ci { 6651cb0ef41Sopenharmony_ci if (exec_quirks == RegExp::ExecQuirks::kTreatMatchAtEndAsFailure) { 6661cb0ef41Sopenharmony_ci static constexpr int kMatchStartOffset = 0; 6671cb0ef41Sopenharmony_ci TNode<IntPtrT> value = ChangeInt32ToIntPtr(UncheckedCast<Int32T>( 6681cb0ef41Sopenharmony_ci Load(MachineType::Int32(), static_offsets_vector_address, 6691cb0ef41Sopenharmony_ci IntPtrConstant(kMatchStartOffset)))); 6701cb0ef41Sopenharmony_ci GotoIf(UintPtrGreaterThanOrEqual(value, int_string_length), &if_failure); 6711cb0ef41Sopenharmony_ci } 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ci // Check that the last match info has space for the capture registers and 6741cb0ef41Sopenharmony_ci // the additional information. Ensure no overflow in add. 6751cb0ef41Sopenharmony_ci STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); 6761cb0ef41Sopenharmony_ci TNode<Smi> available_slots = 6771cb0ef41Sopenharmony_ci SmiSub(LoadFixedArrayBaseLength(match_info), 6781cb0ef41Sopenharmony_ci SmiConstant(RegExpMatchInfo::kLastMatchOverhead)); 6791cb0ef41Sopenharmony_ci TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement( 6801cb0ef41Sopenharmony_ci data, JSRegExp::kIrregexpCaptureCountIndex)); 6811cb0ef41Sopenharmony_ci // Calculate number of register_count = (capture_count + 1) * 2. 6821cb0ef41Sopenharmony_ci TNode<Smi> register_count = 6831cb0ef41Sopenharmony_ci SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1); 6841cb0ef41Sopenharmony_ci GotoIf(SmiGreaterThan(register_count, available_slots), &runtime); 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci // Fill match_info. 6871cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement( 6881cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kNumberOfCapturesIndex, register_count); 6891cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(match_info, RegExpMatchInfo::kLastSubjectIndex, 6901cb0ef41Sopenharmony_ci string); 6911cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(match_info, RegExpMatchInfo::kLastInputIndex, 6921cb0ef41Sopenharmony_ci string); 6931cb0ef41Sopenharmony_ci 6941cb0ef41Sopenharmony_ci // Fill match and capture offsets in match_info. 6951cb0ef41Sopenharmony_ci { 6961cb0ef41Sopenharmony_ci TNode<IntPtrT> limit_offset = 6971cb0ef41Sopenharmony_ci ElementOffsetFromIndex(register_count, INT32_ELEMENTS, 0); 6981cb0ef41Sopenharmony_ci 6991cb0ef41Sopenharmony_ci TNode<IntPtrT> to_offset = ElementOffsetFromIndex( 7001cb0ef41Sopenharmony_ci IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), PACKED_ELEMENTS, 7011cb0ef41Sopenharmony_ci RegExpMatchInfo::kHeaderSize - kHeapObjectTag); 7021cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_to_offset, to_offset); 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ci VariableList vars({&var_to_offset}, zone()); 7051cb0ef41Sopenharmony_ci BuildFastLoop<IntPtrT>( 7061cb0ef41Sopenharmony_ci vars, IntPtrZero(), limit_offset, 7071cb0ef41Sopenharmony_ci [&](TNode<IntPtrT> offset) { 7081cb0ef41Sopenharmony_ci TNode<Int32T> value = UncheckedCast<Int32T>(Load( 7091cb0ef41Sopenharmony_ci MachineType::Int32(), static_offsets_vector_address, offset)); 7101cb0ef41Sopenharmony_ci TNode<Smi> smi_value = SmiFromInt32(value); 7111cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineRepresentation::kTagged, match_info, 7121cb0ef41Sopenharmony_ci var_to_offset.value(), smi_value); 7131cb0ef41Sopenharmony_ci Increment(&var_to_offset, kTaggedSize); 7141cb0ef41Sopenharmony_ci }, 7151cb0ef41Sopenharmony_ci kInt32Size, IndexAdvanceMode::kPost); 7161cb0ef41Sopenharmony_ci } 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci var_result = match_info; 7191cb0ef41Sopenharmony_ci Goto(&out); 7201cb0ef41Sopenharmony_ci } 7211cb0ef41Sopenharmony_ci 7221cb0ef41Sopenharmony_ci BIND(&if_failure); 7231cb0ef41Sopenharmony_ci { 7241cb0ef41Sopenharmony_ci var_result = NullConstant(); 7251cb0ef41Sopenharmony_ci Goto(&out); 7261cb0ef41Sopenharmony_ci } 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ci BIND(&if_exception); 7291cb0ef41Sopenharmony_ci { 7301cb0ef41Sopenharmony_ci// A stack overflow was detected in RegExp code. 7311cb0ef41Sopenharmony_ci#ifdef DEBUG 7321cb0ef41Sopenharmony_ci TNode<ExternalReference> pending_exception_address = 7331cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::Create( 7341cb0ef41Sopenharmony_ci IsolateAddressId::kPendingExceptionAddress, isolate())); 7351cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsTheHole(Load<Object>(pending_exception_address))); 7361cb0ef41Sopenharmony_ci#endif // DEBUG 7371cb0ef41Sopenharmony_ci CallRuntime(Runtime::kThrowStackOverflow, context); 7381cb0ef41Sopenharmony_ci Unreachable(); 7391cb0ef41Sopenharmony_ci } 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_ci BIND(&retry_experimental); 7421cb0ef41Sopenharmony_ci { 7431cb0ef41Sopenharmony_ci auto target_fn = 7441cb0ef41Sopenharmony_ci exec_quirks == RegExp::ExecQuirks::kTreatMatchAtEndAsFailure 7451cb0ef41Sopenharmony_ci ? Runtime::kRegExpExperimentalOneshotExecTreatMatchAtEndAsFailure 7461cb0ef41Sopenharmony_ci : Runtime::kRegExpExperimentalOneshotExec; 7471cb0ef41Sopenharmony_ci var_result = CAST(CallRuntime(target_fn, context, regexp, string, 7481cb0ef41Sopenharmony_ci last_index, match_info)); 7491cb0ef41Sopenharmony_ci Goto(&out); 7501cb0ef41Sopenharmony_ci } 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_ci BIND(&runtime); 7531cb0ef41Sopenharmony_ci { 7541cb0ef41Sopenharmony_ci auto target_fn = 7551cb0ef41Sopenharmony_ci exec_quirks == RegExp::ExecQuirks::kTreatMatchAtEndAsFailure 7561cb0ef41Sopenharmony_ci ? Runtime::kRegExpExecTreatMatchAtEndAsFailure 7571cb0ef41Sopenharmony_ci : Runtime::kRegExpExec; 7581cb0ef41Sopenharmony_ci var_result = CAST(CallRuntime(target_fn, context, regexp, string, 7591cb0ef41Sopenharmony_ci last_index, match_info)); 7601cb0ef41Sopenharmony_ci Goto(&out); 7611cb0ef41Sopenharmony_ci } 7621cb0ef41Sopenharmony_ci 7631cb0ef41Sopenharmony_ci BIND(&atom); 7641cb0ef41Sopenharmony_ci { 7651cb0ef41Sopenharmony_ci // TODO(jgruber): A call with 4 args stresses register allocation, this 7661cb0ef41Sopenharmony_ci // should probably just be inlined. 7671cb0ef41Sopenharmony_ci var_result = CAST(CallBuiltin(Builtin::kRegExpExecAtom, context, regexp, 7681cb0ef41Sopenharmony_ci string, last_index, match_info)); 7691cb0ef41Sopenharmony_ci Goto(&out); 7701cb0ef41Sopenharmony_ci } 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_ci BIND(&out); 7731cb0ef41Sopenharmony_ci return var_result.value(); 7741cb0ef41Sopenharmony_ci} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ciTNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpNoPrototype( 7771cb0ef41Sopenharmony_ci TNode<Context> context, TNode<Object> object, TNode<Map> map) { 7781cb0ef41Sopenharmony_ci Label out(this); 7791cb0ef41Sopenharmony_ci TVARIABLE(BoolT, var_result); 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_FORCE_SLOW_PATH 7821cb0ef41Sopenharmony_ci var_result = Int32FalseConstant(); 7831cb0ef41Sopenharmony_ci GotoIfForceSlowPath(&out); 7841cb0ef41Sopenharmony_ci#endif 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_ci const TNode<NativeContext> native_context = LoadNativeContext(context); 7871cb0ef41Sopenharmony_ci const TNode<HeapObject> regexp_fun = 7881cb0ef41Sopenharmony_ci CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX)); 7891cb0ef41Sopenharmony_ci const TNode<Object> initial_map = 7901cb0ef41Sopenharmony_ci LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 7911cb0ef41Sopenharmony_ci const TNode<BoolT> has_initialmap = TaggedEqual(map, initial_map); 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci var_result = has_initialmap; 7941cb0ef41Sopenharmony_ci GotoIfNot(has_initialmap, &out); 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_ci // The smi check is required to omit ToLength(lastIndex) calls with possible 7971cb0ef41Sopenharmony_ci // user-code execution on the fast path. 7981cb0ef41Sopenharmony_ci TNode<Object> last_index = FastLoadLastIndexBeforeSmiCheck(CAST(object)); 7991cb0ef41Sopenharmony_ci var_result = TaggedIsPositiveSmi(last_index); 8001cb0ef41Sopenharmony_ci Goto(&out); 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_ci BIND(&out); 8031cb0ef41Sopenharmony_ci return var_result.value(); 8041cb0ef41Sopenharmony_ci} 8051cb0ef41Sopenharmony_ci 8061cb0ef41Sopenharmony_ciTNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpNoPrototype( 8071cb0ef41Sopenharmony_ci TNode<Context> context, TNode<Object> object) { 8081cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsNotSmi(object)); 8091cb0ef41Sopenharmony_ci return IsFastRegExpNoPrototype(context, object, LoadMap(CAST(object))); 8101cb0ef41Sopenharmony_ci} 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfFastRegExp( 8131cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> object, TNode<Map> map, 8141cb0ef41Sopenharmony_ci PrototypeCheckAssembler::Flags prototype_check_flags, 8151cb0ef41Sopenharmony_ci base::Optional<DescriptorIndexNameValue> additional_property_to_check, 8161cb0ef41Sopenharmony_ci Label* if_isunmodified, Label* if_ismodified) { 8171cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedEqual(LoadMap(object), map)); 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ci GotoIfForceSlowPath(if_ismodified); 8201cb0ef41Sopenharmony_ci 8211cb0ef41Sopenharmony_ci // This should only be needed for String.p.(split||matchAll), but we are 8221cb0ef41Sopenharmony_ci // conservative here. 8231cb0ef41Sopenharmony_ci GotoIf(IsRegExpSpeciesProtectorCellInvalid(), if_ismodified); 8241cb0ef41Sopenharmony_ci 8251cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(context); 8261cb0ef41Sopenharmony_ci TNode<JSFunction> regexp_fun = 8271cb0ef41Sopenharmony_ci CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX)); 8281cb0ef41Sopenharmony_ci TNode<Map> initial_map = CAST( 8291cb0ef41Sopenharmony_ci LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset)); 8301cb0ef41Sopenharmony_ci TNode<BoolT> has_initialmap = TaggedEqual(map, initial_map); 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_ci GotoIfNot(has_initialmap, if_ismodified); 8331cb0ef41Sopenharmony_ci 8341cb0ef41Sopenharmony_ci // The smi check is required to omit ToLength(lastIndex) calls with possible 8351cb0ef41Sopenharmony_ci // user-code execution on the fast path. 8361cb0ef41Sopenharmony_ci TNode<Object> last_index = FastLoadLastIndexBeforeSmiCheck(CAST(object)); 8371cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsPositiveSmi(last_index), if_ismodified); 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci // Verify the prototype. 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci TNode<Map> initial_proto_initial_map = CAST( 8421cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX)); 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ci DescriptorIndexNameValue properties_to_check[2]; 8451cb0ef41Sopenharmony_ci int property_count = 0; 8461cb0ef41Sopenharmony_ci properties_to_check[property_count++] = DescriptorIndexNameValue{ 8471cb0ef41Sopenharmony_ci JSRegExp::kExecFunctionDescriptorIndex, RootIndex::kexec_string, 8481cb0ef41Sopenharmony_ci Context::REGEXP_EXEC_FUNCTION_INDEX}; 8491cb0ef41Sopenharmony_ci if (additional_property_to_check) { 8501cb0ef41Sopenharmony_ci properties_to_check[property_count++] = *additional_property_to_check; 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ci PrototypeCheckAssembler prototype_check_assembler( 8541cb0ef41Sopenharmony_ci state(), prototype_check_flags, native_context, initial_proto_initial_map, 8551cb0ef41Sopenharmony_ci base::Vector<DescriptorIndexNameValue>(properties_to_check, 8561cb0ef41Sopenharmony_ci property_count)); 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci TNode<HeapObject> prototype = LoadMapPrototype(map); 8591cb0ef41Sopenharmony_ci prototype_check_assembler.CheckAndBranch(prototype, if_isunmodified, 8601cb0ef41Sopenharmony_ci if_ismodified); 8611cb0ef41Sopenharmony_ci} 8621cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfFastRegExpForSearch( 8631cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified, 8641cb0ef41Sopenharmony_ci Label* if_ismodified) { 8651cb0ef41Sopenharmony_ci BranchIfFastRegExp( 8661cb0ef41Sopenharmony_ci context, object, LoadMap(object), 8671cb0ef41Sopenharmony_ci PrototypeCheckAssembler::kCheckPrototypePropertyConstness, 8681cb0ef41Sopenharmony_ci DescriptorIndexNameValue{JSRegExp::kSymbolSearchFunctionDescriptorIndex, 8691cb0ef41Sopenharmony_ci RootIndex::ksearch_symbol, 8701cb0ef41Sopenharmony_ci Context::REGEXP_SEARCH_FUNCTION_INDEX}, 8711cb0ef41Sopenharmony_ci if_isunmodified, if_ismodified); 8721cb0ef41Sopenharmony_ci} 8731cb0ef41Sopenharmony_ci 8741cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfFastRegExpForMatch( 8751cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified, 8761cb0ef41Sopenharmony_ci Label* if_ismodified) { 8771cb0ef41Sopenharmony_ci BranchIfFastRegExp( 8781cb0ef41Sopenharmony_ci context, object, LoadMap(object), 8791cb0ef41Sopenharmony_ci PrototypeCheckAssembler::kCheckPrototypePropertyConstness, 8801cb0ef41Sopenharmony_ci DescriptorIndexNameValue{JSRegExp::kSymbolMatchFunctionDescriptorIndex, 8811cb0ef41Sopenharmony_ci RootIndex::kmatch_symbol, 8821cb0ef41Sopenharmony_ci Context::REGEXP_MATCH_FUNCTION_INDEX}, 8831cb0ef41Sopenharmony_ci if_isunmodified, if_ismodified); 8841cb0ef41Sopenharmony_ci} 8851cb0ef41Sopenharmony_ci 8861cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict( 8871cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified, 8881cb0ef41Sopenharmony_ci Label* if_ismodified) { 8891cb0ef41Sopenharmony_ci BranchIfFastRegExp(context, object, LoadMap(object), 8901cb0ef41Sopenharmony_ci PrototypeCheckAssembler::kCheckPrototypePropertyConstness, 8911cb0ef41Sopenharmony_ci base::nullopt, if_isunmodified, if_ismodified); 8921cb0ef41Sopenharmony_ci} 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive( 8951cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified, 8961cb0ef41Sopenharmony_ci Label* if_ismodified) { 8971cb0ef41Sopenharmony_ci BranchIfFastRegExp(context, object, LoadMap(object), 8981cb0ef41Sopenharmony_ci PrototypeCheckAssembler::kCheckFull, base::nullopt, 8991cb0ef41Sopenharmony_ci if_isunmodified, if_ismodified); 9001cb0ef41Sopenharmony_ci} 9011cb0ef41Sopenharmony_ci 9021cb0ef41Sopenharmony_civoid RegExpBuiltinsAssembler::BranchIfRegExpResult(const TNode<Context> context, 9031cb0ef41Sopenharmony_ci const TNode<Object> object, 9041cb0ef41Sopenharmony_ci Label* if_isunmodified, 9051cb0ef41Sopenharmony_ci Label* if_ismodified) { 9061cb0ef41Sopenharmony_ci // Could be a Smi. 9071cb0ef41Sopenharmony_ci const TNode<Map> map = LoadReceiverMap(object); 9081cb0ef41Sopenharmony_ci 9091cb0ef41Sopenharmony_ci const TNode<NativeContext> native_context = LoadNativeContext(context); 9101cb0ef41Sopenharmony_ci const TNode<Object> initial_regexp_result_map = 9111cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ci Label maybe_result_with_indices(this); 9141cb0ef41Sopenharmony_ci Branch(TaggedEqual(map, initial_regexp_result_map), if_isunmodified, 9151cb0ef41Sopenharmony_ci &maybe_result_with_indices); 9161cb0ef41Sopenharmony_ci BIND(&maybe_result_with_indices); 9171cb0ef41Sopenharmony_ci { 9181cb0ef41Sopenharmony_ci static_assert( 9191cb0ef41Sopenharmony_ci std::is_base_of<JSRegExpResult, JSRegExpResultWithIndices>::value, 9201cb0ef41Sopenharmony_ci "JSRegExpResultWithIndices is a subclass of JSRegExpResult"); 9211cb0ef41Sopenharmony_ci const TNode<Object> initial_regexp_result_with_indices_map = 9221cb0ef41Sopenharmony_ci LoadContextElement(native_context, 9231cb0ef41Sopenharmony_ci Context::REGEXP_RESULT_WITH_INDICES_MAP_INDEX); 9241cb0ef41Sopenharmony_ci Branch(TaggedEqual(map, initial_regexp_result_with_indices_map), 9251cb0ef41Sopenharmony_ci if_isunmodified, if_ismodified); 9261cb0ef41Sopenharmony_ci } 9271cb0ef41Sopenharmony_ci} 9281cb0ef41Sopenharmony_ci 9291cb0ef41Sopenharmony_ci// Fast path stub for ATOM regexps. String matching is done by StringIndexOf, 9301cb0ef41Sopenharmony_ci// and {match_info} is updated on success. 9311cb0ef41Sopenharmony_ci// The slow path is implemented in RegExp::AtomExec. 9321cb0ef41Sopenharmony_ciTF_BUILTIN(RegExpExecAtom, RegExpBuiltinsAssembler) { 9331cb0ef41Sopenharmony_ci auto regexp = Parameter<JSRegExp>(Descriptor::kRegExp); 9341cb0ef41Sopenharmony_ci auto subject_string = Parameter<String>(Descriptor::kString); 9351cb0ef41Sopenharmony_ci auto last_index = Parameter<Smi>(Descriptor::kLastIndex); 9361cb0ef41Sopenharmony_ci auto match_info = Parameter<FixedArray>(Descriptor::kMatchInfo); 9371cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 9381cb0ef41Sopenharmony_ci 9391cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsPositiveSmi(last_index)); 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ci TNode<FixedArray> data = CAST(LoadObjectField(regexp, JSRegExp::kDataOffset)); 9421cb0ef41Sopenharmony_ci CSA_DCHECK( 9431cb0ef41Sopenharmony_ci this, 9441cb0ef41Sopenharmony_ci SmiEqual(CAST(UnsafeLoadFixedArrayElement(data, JSRegExp::kTagIndex)), 9451cb0ef41Sopenharmony_ci SmiConstant(JSRegExp::ATOM))); 9461cb0ef41Sopenharmony_ci 9471cb0ef41Sopenharmony_ci // Callers ensure that last_index is in-bounds. 9481cb0ef41Sopenharmony_ci CSA_DCHECK(this, 9491cb0ef41Sopenharmony_ci UintPtrLessThanOrEqual(SmiUntag(last_index), 9501cb0ef41Sopenharmony_ci LoadStringLengthAsWord(subject_string))); 9511cb0ef41Sopenharmony_ci 9521cb0ef41Sopenharmony_ci const TNode<String> needle_string = 9531cb0ef41Sopenharmony_ci CAST(UnsafeLoadFixedArrayElement(data, JSRegExp::kAtomPatternIndex)); 9541cb0ef41Sopenharmony_ci 9551cb0ef41Sopenharmony_ci // ATOM patterns are guaranteed to not be the empty string (these are 9561cb0ef41Sopenharmony_ci // intercepted and replaced in JSRegExp::Initialize. 9571cb0ef41Sopenharmony_ci // 9581cb0ef41Sopenharmony_ci // This is especially relevant for crbug.com/1075514: atom patterns are 9591cb0ef41Sopenharmony_ci // non-empty and thus guaranteed not to match at the end of the string. 9601cb0ef41Sopenharmony_ci CSA_DCHECK(this, IntPtrGreaterThan(LoadStringLengthAsWord(needle_string), 9611cb0ef41Sopenharmony_ci IntPtrConstant(0))); 9621cb0ef41Sopenharmony_ci 9631cb0ef41Sopenharmony_ci const TNode<Smi> match_from = 9641cb0ef41Sopenharmony_ci CAST(CallBuiltin(Builtin::kStringIndexOf, context, subject_string, 9651cb0ef41Sopenharmony_ci needle_string, last_index)); 9661cb0ef41Sopenharmony_ci 9671cb0ef41Sopenharmony_ci Label if_failure(this), if_success(this); 9681cb0ef41Sopenharmony_ci Branch(SmiEqual(match_from, SmiConstant(-1)), &if_failure, &if_success); 9691cb0ef41Sopenharmony_ci 9701cb0ef41Sopenharmony_ci BIND(&if_success); 9711cb0ef41Sopenharmony_ci { 9721cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsPositiveSmi(match_from)); 9731cb0ef41Sopenharmony_ci CSA_DCHECK(this, UintPtrLessThan(SmiUntag(match_from), 9741cb0ef41Sopenharmony_ci LoadStringLengthAsWord(subject_string))); 9751cb0ef41Sopenharmony_ci 9761cb0ef41Sopenharmony_ci const int kNumRegisters = 2; 9771cb0ef41Sopenharmony_ci STATIC_ASSERT(RegExpMatchInfo::kInitialCaptureIndices >= kNumRegisters); 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_ci const TNode<Smi> match_to = 9801cb0ef41Sopenharmony_ci SmiAdd(match_from, LoadStringLengthAsSmi(needle_string)); 9811cb0ef41Sopenharmony_ci 9821cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(match_info, 9831cb0ef41Sopenharmony_ci RegExpMatchInfo::kNumberOfCapturesIndex, 9841cb0ef41Sopenharmony_ci SmiConstant(kNumRegisters)); 9851cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(match_info, RegExpMatchInfo::kLastSubjectIndex, 9861cb0ef41Sopenharmony_ci subject_string); 9871cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(match_info, RegExpMatchInfo::kLastInputIndex, 9881cb0ef41Sopenharmony_ci subject_string); 9891cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement( 9901cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kFirstCaptureIndex, match_from); 9911cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement( 9921cb0ef41Sopenharmony_ci match_info, RegExpMatchInfo::kFirstCaptureIndex + 1, match_to); 9931cb0ef41Sopenharmony_ci 9941cb0ef41Sopenharmony_ci Return(match_info); 9951cb0ef41Sopenharmony_ci } 9961cb0ef41Sopenharmony_ci 9971cb0ef41Sopenharmony_ci BIND(&if_failure); 9981cb0ef41Sopenharmony_ci Return(NullConstant()); 9991cb0ef41Sopenharmony_ci} 10001cb0ef41Sopenharmony_ci 10011cb0ef41Sopenharmony_ciTF_BUILTIN(RegExpExecInternal, RegExpBuiltinsAssembler) { 10021cb0ef41Sopenharmony_ci auto regexp = Parameter<JSRegExp>(Descriptor::kRegExp); 10031cb0ef41Sopenharmony_ci auto string = Parameter<String>(Descriptor::kString); 10041cb0ef41Sopenharmony_ci auto last_index = Parameter<Number>(Descriptor::kLastIndex); 10051cb0ef41Sopenharmony_ci auto match_info = Parameter<RegExpMatchInfo>(Descriptor::kMatchInfo); 10061cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 10071cb0ef41Sopenharmony_ci 10081cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberNormalized(last_index)); 10091cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberPositive(last_index)); 10101cb0ef41Sopenharmony_ci 10111cb0ef41Sopenharmony_ci Return(RegExpExecInternal(context, regexp, string, last_index, match_info)); 10121cb0ef41Sopenharmony_ci} 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ciTNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context, 10151cb0ef41Sopenharmony_ci TNode<Object> regexp, 10161cb0ef41Sopenharmony_ci bool is_fastpath) { 10171cb0ef41Sopenharmony_ci TVARIABLE(String, result); 10181cb0ef41Sopenharmony_ci Label runtime(this, Label::kDeferred), done(this, &result); 10191cb0ef41Sopenharmony_ci if (is_fastpath) { 10201cb0ef41Sopenharmony_ci GotoIfForceSlowPath(&runtime); 10211cb0ef41Sopenharmony_ci } 10221cb0ef41Sopenharmony_ci 10231cb0ef41Sopenharmony_ci Isolate* isolate = this->isolate(); 10241cb0ef41Sopenharmony_ci 10251cb0ef41Sopenharmony_ci const TNode<IntPtrT> int_one = IntPtrConstant(1); 10261cb0ef41Sopenharmony_ci TVARIABLE(Uint32T, var_length, Uint32Constant(0)); 10271cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_flags); 10281cb0ef41Sopenharmony_ci 10291cb0ef41Sopenharmony_ci // First, count the number of characters we will need and check which flags 10301cb0ef41Sopenharmony_ci // are set. 10311cb0ef41Sopenharmony_ci 10321cb0ef41Sopenharmony_ci if (is_fastpath) { 10331cb0ef41Sopenharmony_ci // Refer to JSRegExp's flag property on the fast-path. 10341cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsJSRegExp(CAST(regexp))); 10351cb0ef41Sopenharmony_ci const TNode<Smi> flags_smi = 10361cb0ef41Sopenharmony_ci CAST(LoadObjectField(CAST(regexp), JSRegExp::kFlagsOffset)); 10371cb0ef41Sopenharmony_ci var_flags = SmiUntag(flags_smi); 10381cb0ef41Sopenharmony_ci 10391cb0ef41Sopenharmony_ci#define CASE_FOR_FLAG(Lower, Camel, ...) \ 10401cb0ef41Sopenharmony_ci do { \ 10411cb0ef41Sopenharmony_ci Label next(this); \ 10421cb0ef41Sopenharmony_ci GotoIfNot(IsSetWord(var_flags.value(), JSRegExp::k##Camel), &next); \ 10431cb0ef41Sopenharmony_ci var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \ 10441cb0ef41Sopenharmony_ci Goto(&next); \ 10451cb0ef41Sopenharmony_ci BIND(&next); \ 10461cb0ef41Sopenharmony_ci } while (false); 10471cb0ef41Sopenharmony_ci 10481cb0ef41Sopenharmony_ci REGEXP_FLAG_LIST(CASE_FOR_FLAG) 10491cb0ef41Sopenharmony_ci#undef CASE_FOR_FLAG 10501cb0ef41Sopenharmony_ci } else { 10511cb0ef41Sopenharmony_ci DCHECK(!is_fastpath); 10521cb0ef41Sopenharmony_ci 10531cb0ef41Sopenharmony_ci // Fall back to GetProperty stub on the slow-path. 10541cb0ef41Sopenharmony_ci var_flags = IntPtrZero(); 10551cb0ef41Sopenharmony_ci 10561cb0ef41Sopenharmony_ci#define CASE_FOR_FLAG(NAME, FLAG) \ 10571cb0ef41Sopenharmony_ci do { \ 10581cb0ef41Sopenharmony_ci Label next(this); \ 10591cb0ef41Sopenharmony_ci const TNode<Object> flag = GetProperty( \ 10601cb0ef41Sopenharmony_ci context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \ 10611cb0ef41Sopenharmony_ci Label if_isflagset(this); \ 10621cb0ef41Sopenharmony_ci BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \ 10631cb0ef41Sopenharmony_ci BIND(&if_isflagset); \ 10641cb0ef41Sopenharmony_ci var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \ 10651cb0ef41Sopenharmony_ci var_flags = Signed(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \ 10661cb0ef41Sopenharmony_ci Goto(&next); \ 10671cb0ef41Sopenharmony_ci BIND(&next); \ 10681cb0ef41Sopenharmony_ci } while (false) 10691cb0ef41Sopenharmony_ci 10701cb0ef41Sopenharmony_ci CASE_FOR_FLAG("global", JSRegExp::kGlobal); 10711cb0ef41Sopenharmony_ci CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase); 10721cb0ef41Sopenharmony_ci CASE_FOR_FLAG("multiline", JSRegExp::kMultiline); 10731cb0ef41Sopenharmony_ci CASE_FOR_FLAG("dotAll", JSRegExp::kDotAll); 10741cb0ef41Sopenharmony_ci CASE_FOR_FLAG("unicode", JSRegExp::kUnicode); 10751cb0ef41Sopenharmony_ci CASE_FOR_FLAG("sticky", JSRegExp::kSticky); 10761cb0ef41Sopenharmony_ci CASE_FOR_FLAG("hasIndices", JSRegExp::kHasIndices); 10771cb0ef41Sopenharmony_ci#undef CASE_FOR_FLAG 10781cb0ef41Sopenharmony_ci 10791cb0ef41Sopenharmony_ci#define CASE_FOR_FLAG(NAME, V8_FLAG_EXTERN_REF, FLAG) \ 10801cb0ef41Sopenharmony_ci do { \ 10811cb0ef41Sopenharmony_ci Label next(this); \ 10821cb0ef41Sopenharmony_ci TNode<Word32T> flag_value = UncheckedCast<Word32T>( \ 10831cb0ef41Sopenharmony_ci Load(MachineType::Uint8(), ExternalConstant(V8_FLAG_EXTERN_REF))); \ 10841cb0ef41Sopenharmony_ci GotoIf(Word32Equal(Word32And(flag_value, Int32Constant(0xFF)), \ 10851cb0ef41Sopenharmony_ci Int32Constant(0)), \ 10861cb0ef41Sopenharmony_ci &next); \ 10871cb0ef41Sopenharmony_ci const TNode<Object> flag = GetProperty( \ 10881cb0ef41Sopenharmony_ci context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \ 10891cb0ef41Sopenharmony_ci Label if_isflagset(this); \ 10901cb0ef41Sopenharmony_ci BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \ 10911cb0ef41Sopenharmony_ci BIND(&if_isflagset); \ 10921cb0ef41Sopenharmony_ci var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \ 10931cb0ef41Sopenharmony_ci var_flags = Signed(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \ 10941cb0ef41Sopenharmony_ci Goto(&next); \ 10951cb0ef41Sopenharmony_ci BIND(&next); \ 10961cb0ef41Sopenharmony_ci } while (false) 10971cb0ef41Sopenharmony_ci 10981cb0ef41Sopenharmony_ci CASE_FOR_FLAG( 10991cb0ef41Sopenharmony_ci "linear", 11001cb0ef41Sopenharmony_ci ExternalReference::address_of_enable_experimental_regexp_engine(), 11011cb0ef41Sopenharmony_ci JSRegExp::kLinear); 11021cb0ef41Sopenharmony_ci#undef CASE_FOR_FLAG 11031cb0ef41Sopenharmony_ci } 11041cb0ef41Sopenharmony_ci 11051cb0ef41Sopenharmony_ci // Allocate a string of the required length and fill it with the 11061cb0ef41Sopenharmony_ci // corresponding char for each set flag. 11071cb0ef41Sopenharmony_ci 11081cb0ef41Sopenharmony_ci { 11091cb0ef41Sopenharmony_ci const TNode<String> string = AllocateSeqOneByteString(var_length.value()); 11101cb0ef41Sopenharmony_ci 11111cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_offset, 11121cb0ef41Sopenharmony_ci IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 11131cb0ef41Sopenharmony_ci 11141cb0ef41Sopenharmony_ci#define CASE_FOR_FLAG(Lower, Camel, LowerCamel, Char, ...) \ 11151cb0ef41Sopenharmony_ci do { \ 11161cb0ef41Sopenharmony_ci Label next(this); \ 11171cb0ef41Sopenharmony_ci GotoIfNot(IsSetWord(var_flags.value(), JSRegExp::k##Camel), &next); \ 11181cb0ef41Sopenharmony_ci const TNode<Int32T> value = Int32Constant(Char); \ 11191cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineRepresentation::kWord8, string, \ 11201cb0ef41Sopenharmony_ci var_offset.value(), value); \ 11211cb0ef41Sopenharmony_ci var_offset = IntPtrAdd(var_offset.value(), int_one); \ 11221cb0ef41Sopenharmony_ci Goto(&next); \ 11231cb0ef41Sopenharmony_ci BIND(&next); \ 11241cb0ef41Sopenharmony_ci } while (false); 11251cb0ef41Sopenharmony_ci 11261cb0ef41Sopenharmony_ci REGEXP_FLAG_LIST(CASE_FOR_FLAG) 11271cb0ef41Sopenharmony_ci#undef CASE_FOR_FLAG 11281cb0ef41Sopenharmony_ci 11291cb0ef41Sopenharmony_ci if (is_fastpath) { 11301cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_FORCE_SLOW_PATH 11311cb0ef41Sopenharmony_ci result = string; 11321cb0ef41Sopenharmony_ci Goto(&done); 11331cb0ef41Sopenharmony_ci 11341cb0ef41Sopenharmony_ci BIND(&runtime); 11351cb0ef41Sopenharmony_ci { 11361cb0ef41Sopenharmony_ci result = 11371cb0ef41Sopenharmony_ci CAST(CallRuntime(Runtime::kRegExpStringFromFlags, context, regexp)); 11381cb0ef41Sopenharmony_ci Goto(&done); 11391cb0ef41Sopenharmony_ci } 11401cb0ef41Sopenharmony_ci 11411cb0ef41Sopenharmony_ci BIND(&done); 11421cb0ef41Sopenharmony_ci return result.value(); 11431cb0ef41Sopenharmony_ci#else 11441cb0ef41Sopenharmony_ci return string; 11451cb0ef41Sopenharmony_ci#endif 11461cb0ef41Sopenharmony_ci } else { 11471cb0ef41Sopenharmony_ci return string; 11481cb0ef41Sopenharmony_ci } 11491cb0ef41Sopenharmony_ci } 11501cb0ef41Sopenharmony_ci} 11511cb0ef41Sopenharmony_ci 11521cb0ef41Sopenharmony_ci// ES#sec-regexpinitialize 11531cb0ef41Sopenharmony_ci// Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) 11541cb0ef41Sopenharmony_ciTNode<Object> RegExpBuiltinsAssembler::RegExpInitialize( 11551cb0ef41Sopenharmony_ci const TNode<Context> context, const TNode<JSRegExp> regexp, 11561cb0ef41Sopenharmony_ci const TNode<Object> maybe_pattern, const TNode<Object> maybe_flags) { 11571cb0ef41Sopenharmony_ci // Normalize pattern. 11581cb0ef41Sopenharmony_ci const TNode<Object> pattern = Select<Object>( 11591cb0ef41Sopenharmony_ci IsUndefined(maybe_pattern), [=] { return EmptyStringConstant(); }, 11601cb0ef41Sopenharmony_ci [=] { return ToString_Inline(context, maybe_pattern); }); 11611cb0ef41Sopenharmony_ci 11621cb0ef41Sopenharmony_ci // Normalize flags. 11631cb0ef41Sopenharmony_ci const TNode<Object> flags = Select<Object>( 11641cb0ef41Sopenharmony_ci IsUndefined(maybe_flags), [=] { return EmptyStringConstant(); }, 11651cb0ef41Sopenharmony_ci [=] { return ToString_Inline(context, maybe_flags); }); 11661cb0ef41Sopenharmony_ci 11671cb0ef41Sopenharmony_ci // Initialize. 11681cb0ef41Sopenharmony_ci 11691cb0ef41Sopenharmony_ci return CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp, 11701cb0ef41Sopenharmony_ci pattern, flags); 11711cb0ef41Sopenharmony_ci} 11721cb0ef41Sopenharmony_ci 11731cb0ef41Sopenharmony_ci// ES#sec-regexp-pattern-flags 11741cb0ef41Sopenharmony_ci// RegExp ( pattern, flags ) 11751cb0ef41Sopenharmony_ciTF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) { 11761cb0ef41Sopenharmony_ci auto pattern = Parameter<Object>(Descriptor::kPattern); 11771cb0ef41Sopenharmony_ci auto flags = Parameter<Object>(Descriptor::kFlags); 11781cb0ef41Sopenharmony_ci auto new_target = Parameter<Object>(Descriptor::kJSNewTarget); 11791cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 11801cb0ef41Sopenharmony_ci 11811cb0ef41Sopenharmony_ci Isolate* isolate = this->isolate(); 11821cb0ef41Sopenharmony_ci 11831cb0ef41Sopenharmony_ci TVARIABLE(Object, var_flags, flags); 11841cb0ef41Sopenharmony_ci TVARIABLE(Object, var_pattern, pattern); 11851cb0ef41Sopenharmony_ci TVARIABLE(Object, var_new_target, new_target); 11861cb0ef41Sopenharmony_ci 11871cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(context); 11881cb0ef41Sopenharmony_ci TNode<JSFunction> regexp_function = 11891cb0ef41Sopenharmony_ci CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX)); 11901cb0ef41Sopenharmony_ci 11911cb0ef41Sopenharmony_ci TNode<BoolT> pattern_is_regexp = IsRegExp(context, pattern); 11921cb0ef41Sopenharmony_ci 11931cb0ef41Sopenharmony_ci { 11941cb0ef41Sopenharmony_ci Label next(this); 11951cb0ef41Sopenharmony_ci 11961cb0ef41Sopenharmony_ci GotoIfNot(IsUndefined(new_target), &next); 11971cb0ef41Sopenharmony_ci var_new_target = regexp_function; 11981cb0ef41Sopenharmony_ci 11991cb0ef41Sopenharmony_ci GotoIfNot(pattern_is_regexp, &next); 12001cb0ef41Sopenharmony_ci GotoIfNot(IsUndefined(flags), &next); 12011cb0ef41Sopenharmony_ci 12021cb0ef41Sopenharmony_ci TNode<Object> value = 12031cb0ef41Sopenharmony_ci GetProperty(context, pattern, isolate->factory()->constructor_string()); 12041cb0ef41Sopenharmony_ci 12051cb0ef41Sopenharmony_ci GotoIfNot(TaggedEqual(value, regexp_function), &next); 12061cb0ef41Sopenharmony_ci Return(pattern); 12071cb0ef41Sopenharmony_ci 12081cb0ef41Sopenharmony_ci BIND(&next); 12091cb0ef41Sopenharmony_ci } 12101cb0ef41Sopenharmony_ci 12111cb0ef41Sopenharmony_ci { 12121cb0ef41Sopenharmony_ci Label next(this), if_patternisfastregexp(this), 12131cb0ef41Sopenharmony_ci if_patternisslowregexp(this); 12141cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(pattern), &next); 12151cb0ef41Sopenharmony_ci 12161cb0ef41Sopenharmony_ci GotoIf(IsJSRegExp(CAST(pattern)), &if_patternisfastregexp); 12171cb0ef41Sopenharmony_ci 12181cb0ef41Sopenharmony_ci Branch(pattern_is_regexp, &if_patternisslowregexp, &next); 12191cb0ef41Sopenharmony_ci 12201cb0ef41Sopenharmony_ci BIND(&if_patternisfastregexp); 12211cb0ef41Sopenharmony_ci { 12221cb0ef41Sopenharmony_ci TNode<Object> source = 12231cb0ef41Sopenharmony_ci LoadObjectField(CAST(pattern), JSRegExp::kSourceOffset); 12241cb0ef41Sopenharmony_ci var_pattern = source; 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci { 12271cb0ef41Sopenharmony_ci Label inner_next(this); 12281cb0ef41Sopenharmony_ci GotoIfNot(IsUndefined(flags), &inner_next); 12291cb0ef41Sopenharmony_ci 12301cb0ef41Sopenharmony_ci var_flags = FlagsGetter(context, pattern, true); 12311cb0ef41Sopenharmony_ci Goto(&inner_next); 12321cb0ef41Sopenharmony_ci 12331cb0ef41Sopenharmony_ci BIND(&inner_next); 12341cb0ef41Sopenharmony_ci } 12351cb0ef41Sopenharmony_ci 12361cb0ef41Sopenharmony_ci Goto(&next); 12371cb0ef41Sopenharmony_ci } 12381cb0ef41Sopenharmony_ci 12391cb0ef41Sopenharmony_ci BIND(&if_patternisslowregexp); 12401cb0ef41Sopenharmony_ci { 12411cb0ef41Sopenharmony_ci var_pattern = 12421cb0ef41Sopenharmony_ci GetProperty(context, pattern, isolate->factory()->source_string()); 12431cb0ef41Sopenharmony_ci 12441cb0ef41Sopenharmony_ci { 12451cb0ef41Sopenharmony_ci Label inner_next(this); 12461cb0ef41Sopenharmony_ci GotoIfNot(IsUndefined(flags), &inner_next); 12471cb0ef41Sopenharmony_ci 12481cb0ef41Sopenharmony_ci var_flags = 12491cb0ef41Sopenharmony_ci GetProperty(context, pattern, isolate->factory()->flags_string()); 12501cb0ef41Sopenharmony_ci Goto(&inner_next); 12511cb0ef41Sopenharmony_ci 12521cb0ef41Sopenharmony_ci BIND(&inner_next); 12531cb0ef41Sopenharmony_ci } 12541cb0ef41Sopenharmony_ci 12551cb0ef41Sopenharmony_ci Goto(&next); 12561cb0ef41Sopenharmony_ci } 12571cb0ef41Sopenharmony_ci 12581cb0ef41Sopenharmony_ci BIND(&next); 12591cb0ef41Sopenharmony_ci } 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci // Allocate. 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_ci TVARIABLE(JSRegExp, var_regexp); 12641cb0ef41Sopenharmony_ci { 12651cb0ef41Sopenharmony_ci Label allocate_jsregexp(this), allocate_generic(this, Label::kDeferred), 12661cb0ef41Sopenharmony_ci next(this); 12671cb0ef41Sopenharmony_ci Branch(TaggedEqual(var_new_target.value(), regexp_function), 12681cb0ef41Sopenharmony_ci &allocate_jsregexp, &allocate_generic); 12691cb0ef41Sopenharmony_ci 12701cb0ef41Sopenharmony_ci BIND(&allocate_jsregexp); 12711cb0ef41Sopenharmony_ci { 12721cb0ef41Sopenharmony_ci const TNode<Map> initial_map = CAST(LoadObjectField( 12731cb0ef41Sopenharmony_ci regexp_function, JSFunction::kPrototypeOrInitialMapOffset)); 12741cb0ef41Sopenharmony_ci var_regexp = CAST(AllocateJSObjectFromMap(initial_map)); 12751cb0ef41Sopenharmony_ci Goto(&next); 12761cb0ef41Sopenharmony_ci } 12771cb0ef41Sopenharmony_ci 12781cb0ef41Sopenharmony_ci BIND(&allocate_generic); 12791cb0ef41Sopenharmony_ci { 12801cb0ef41Sopenharmony_ci ConstructorBuiltinsAssembler constructor_assembler(this->state()); 12811cb0ef41Sopenharmony_ci var_regexp = CAST(constructor_assembler.FastNewObject( 12821cb0ef41Sopenharmony_ci context, regexp_function, CAST(var_new_target.value()))); 12831cb0ef41Sopenharmony_ci Goto(&next); 12841cb0ef41Sopenharmony_ci } 12851cb0ef41Sopenharmony_ci 12861cb0ef41Sopenharmony_ci BIND(&next); 12871cb0ef41Sopenharmony_ci } 12881cb0ef41Sopenharmony_ci 12891cb0ef41Sopenharmony_ci const TNode<Object> result = RegExpInitialize( 12901cb0ef41Sopenharmony_ci context, var_regexp.value(), var_pattern.value(), var_flags.value()); 12911cb0ef41Sopenharmony_ci Return(result); 12921cb0ef41Sopenharmony_ci} 12931cb0ef41Sopenharmony_ci 12941cb0ef41Sopenharmony_ci// ES#sec-regexp.prototype.compile 12951cb0ef41Sopenharmony_ci// RegExp.prototype.compile ( pattern, flags ) 12961cb0ef41Sopenharmony_ciTF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) { 12971cb0ef41Sopenharmony_ci auto maybe_receiver = Parameter<Object>(Descriptor::kReceiver); 12981cb0ef41Sopenharmony_ci auto maybe_pattern = Parameter<Object>(Descriptor::kPattern); 12991cb0ef41Sopenharmony_ci auto maybe_flags = Parameter<Object>(Descriptor::kFlags); 13001cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 13011cb0ef41Sopenharmony_ci 13021cb0ef41Sopenharmony_ci ThrowIfNotInstanceType(context, maybe_receiver, JS_REG_EXP_TYPE, 13031cb0ef41Sopenharmony_ci "RegExp.prototype.compile"); 13041cb0ef41Sopenharmony_ci const TNode<JSRegExp> receiver = CAST(maybe_receiver); 13051cb0ef41Sopenharmony_ci 13061cb0ef41Sopenharmony_ci TVARIABLE(Object, var_flags, maybe_flags); 13071cb0ef41Sopenharmony_ci TVARIABLE(Object, var_pattern, maybe_pattern); 13081cb0ef41Sopenharmony_ci 13091cb0ef41Sopenharmony_ci // Handle a JSRegExp pattern. 13101cb0ef41Sopenharmony_ci { 13111cb0ef41Sopenharmony_ci Label next(this); 13121cb0ef41Sopenharmony_ci 13131cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(maybe_pattern), &next); 13141cb0ef41Sopenharmony_ci GotoIfNot(IsJSRegExp(CAST(maybe_pattern)), &next); 13151cb0ef41Sopenharmony_ci 13161cb0ef41Sopenharmony_ci // {maybe_flags} must be undefined in this case, otherwise throw. 13171cb0ef41Sopenharmony_ci { 13181cb0ef41Sopenharmony_ci Label maybe_flags_is_undefined(this); 13191cb0ef41Sopenharmony_ci GotoIf(IsUndefined(maybe_flags), &maybe_flags_is_undefined); 13201cb0ef41Sopenharmony_ci 13211cb0ef41Sopenharmony_ci ThrowTypeError(context, MessageTemplate::kRegExpFlags); 13221cb0ef41Sopenharmony_ci 13231cb0ef41Sopenharmony_ci BIND(&maybe_flags_is_undefined); 13241cb0ef41Sopenharmony_ci } 13251cb0ef41Sopenharmony_ci 13261cb0ef41Sopenharmony_ci const TNode<JSRegExp> pattern = CAST(maybe_pattern); 13271cb0ef41Sopenharmony_ci const TNode<String> new_flags = FlagsGetter(context, pattern, true); 13281cb0ef41Sopenharmony_ci const TNode<Object> new_pattern = 13291cb0ef41Sopenharmony_ci LoadObjectField(pattern, JSRegExp::kSourceOffset); 13301cb0ef41Sopenharmony_ci 13311cb0ef41Sopenharmony_ci var_flags = new_flags; 13321cb0ef41Sopenharmony_ci var_pattern = new_pattern; 13331cb0ef41Sopenharmony_ci 13341cb0ef41Sopenharmony_ci Goto(&next); 13351cb0ef41Sopenharmony_ci BIND(&next); 13361cb0ef41Sopenharmony_ci } 13371cb0ef41Sopenharmony_ci 13381cb0ef41Sopenharmony_ci const TNode<Object> result = RegExpInitialize( 13391cb0ef41Sopenharmony_ci context, receiver, var_pattern.value(), var_flags.value()); 13401cb0ef41Sopenharmony_ci Return(result); 13411cb0ef41Sopenharmony_ci} 13421cb0ef41Sopenharmony_ci 13431cb0ef41Sopenharmony_ci// Fast-path implementation for flag checks on an unmodified JSRegExp instance. 13441cb0ef41Sopenharmony_ciTNode<BoolT> RegExpBuiltinsAssembler::FastFlagGetter(TNode<JSRegExp> regexp, 13451cb0ef41Sopenharmony_ci JSRegExp::Flag flag) { 13461cb0ef41Sopenharmony_ci TNode<Smi> flags = CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset)); 13471cb0ef41Sopenharmony_ci TNode<Smi> mask = SmiConstant(flag); 13481cb0ef41Sopenharmony_ci return ReinterpretCast<BoolT>(SmiToInt32( 13491cb0ef41Sopenharmony_ci SmiShr(SmiAnd(flags, mask), 13501cb0ef41Sopenharmony_ci base::bits::CountTrailingZeros(static_cast<int>(flag))))); 13511cb0ef41Sopenharmony_ci} 13521cb0ef41Sopenharmony_ci 13531cb0ef41Sopenharmony_ci// Load through the GetProperty stub. 13541cb0ef41Sopenharmony_ciTNode<BoolT> RegExpBuiltinsAssembler::SlowFlagGetter(TNode<Context> context, 13551cb0ef41Sopenharmony_ci TNode<Object> regexp, 13561cb0ef41Sopenharmony_ci JSRegExp::Flag flag) { 13571cb0ef41Sopenharmony_ci Label out(this), if_true(this), if_false(this); 13581cb0ef41Sopenharmony_ci TVARIABLE(BoolT, var_result); 13591cb0ef41Sopenharmony_ci 13601cb0ef41Sopenharmony_ci // Only enabled based on a runtime flag. 13611cb0ef41Sopenharmony_ci if (flag == JSRegExp::kLinear) { 13621cb0ef41Sopenharmony_ci TNode<Word32T> flag_value = UncheckedCast<Word32T>(Load( 13631cb0ef41Sopenharmony_ci MachineType::Uint8(), 13641cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference:: 13651cb0ef41Sopenharmony_ci address_of_enable_experimental_regexp_engine()))); 13661cb0ef41Sopenharmony_ci GotoIf(Word32Equal(Word32And(flag_value, Int32Constant(0xFF)), 13671cb0ef41Sopenharmony_ci Int32Constant(0)), 13681cb0ef41Sopenharmony_ci &if_false); 13691cb0ef41Sopenharmony_ci } 13701cb0ef41Sopenharmony_ci 13711cb0ef41Sopenharmony_ci Handle<String> name; 13721cb0ef41Sopenharmony_ci switch (flag) { 13731cb0ef41Sopenharmony_ci case JSRegExp::kNone: 13741cb0ef41Sopenharmony_ci UNREACHABLE(); 13751cb0ef41Sopenharmony_ci#define V(Lower, Camel, LowerCamel, Char, Bit) \ 13761cb0ef41Sopenharmony_ci case JSRegExp::k##Camel: \ 13771cb0ef41Sopenharmony_ci name = isolate()->factory()->LowerCamel##_string(); \ 13781cb0ef41Sopenharmony_ci break; 13791cb0ef41Sopenharmony_ci REGEXP_FLAG_LIST(V) 13801cb0ef41Sopenharmony_ci#undef V 13811cb0ef41Sopenharmony_ci } 13821cb0ef41Sopenharmony_ci 13831cb0ef41Sopenharmony_ci TNode<Object> value = GetProperty(context, regexp, name); 13841cb0ef41Sopenharmony_ci BranchIfToBooleanIsTrue(value, &if_true, &if_false); 13851cb0ef41Sopenharmony_ci 13861cb0ef41Sopenharmony_ci BIND(&if_true); 13871cb0ef41Sopenharmony_ci var_result = BoolConstant(true); 13881cb0ef41Sopenharmony_ci Goto(&out); 13891cb0ef41Sopenharmony_ci 13901cb0ef41Sopenharmony_ci BIND(&if_false); 13911cb0ef41Sopenharmony_ci var_result = BoolConstant(false); 13921cb0ef41Sopenharmony_ci Goto(&out); 13931cb0ef41Sopenharmony_ci 13941cb0ef41Sopenharmony_ci BIND(&out); 13951cb0ef41Sopenharmony_ci return var_result.value(); 13961cb0ef41Sopenharmony_ci} 13971cb0ef41Sopenharmony_ci 13981cb0ef41Sopenharmony_ciTNode<BoolT> RegExpBuiltinsAssembler::FlagGetter(TNode<Context> context, 13991cb0ef41Sopenharmony_ci TNode<Object> regexp, 14001cb0ef41Sopenharmony_ci JSRegExp::Flag flag, 14011cb0ef41Sopenharmony_ci bool is_fastpath) { 14021cb0ef41Sopenharmony_ci return is_fastpath ? FastFlagGetter(CAST(regexp), flag) 14031cb0ef41Sopenharmony_ci : SlowFlagGetter(context, regexp, flag); 14041cb0ef41Sopenharmony_ci} 14051cb0ef41Sopenharmony_ci 14061cb0ef41Sopenharmony_ciTNode<Number> RegExpBuiltinsAssembler::AdvanceStringIndex( 14071cb0ef41Sopenharmony_ci TNode<String> string, TNode<Number> index, TNode<BoolT> is_unicode, 14081cb0ef41Sopenharmony_ci bool is_fastpath) { 14091cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberNormalized(index)); 14101cb0ef41Sopenharmony_ci if (is_fastpath) CSA_DCHECK(this, TaggedIsPositiveSmi(index)); 14111cb0ef41Sopenharmony_ci 14121cb0ef41Sopenharmony_ci // Default to last_index + 1. 14131cb0ef41Sopenharmony_ci // TODO(pwong): Consider using TrySmiAdd for the fast path to reduce generated 14141cb0ef41Sopenharmony_ci // code. 14151cb0ef41Sopenharmony_ci TNode<Number> index_plus_one = NumberInc(index); 14161cb0ef41Sopenharmony_ci TVARIABLE(Number, var_result, index_plus_one); 14171cb0ef41Sopenharmony_ci 14181cb0ef41Sopenharmony_ci // TODO(v8:9880): Given that we have to convert index from Number to UintPtrT 14191cb0ef41Sopenharmony_ci // anyway, consider using UintPtrT index to simplify the code below. 14201cb0ef41Sopenharmony_ci 14211cb0ef41Sopenharmony_ci // Advancing the index has some subtle issues involving the distinction 14221cb0ef41Sopenharmony_ci // between Smis and HeapNumbers. There's three cases: 14231cb0ef41Sopenharmony_ci // * {index} is a Smi, {index_plus_one} is a Smi. The standard case. 14241cb0ef41Sopenharmony_ci // * {index} is a Smi, {index_plus_one} overflows into a HeapNumber. 14251cb0ef41Sopenharmony_ci // In this case we can return the result early, because 14261cb0ef41Sopenharmony_ci // {index_plus_one} > {string}.length. 14271cb0ef41Sopenharmony_ci // * {index} is a HeapNumber, {index_plus_one} is a HeapNumber. This can only 14281cb0ef41Sopenharmony_ci // occur when {index} is outside the Smi range since we normalize 14291cb0ef41Sopenharmony_ci // explicitly. Again we can return early. 14301cb0ef41Sopenharmony_ci if (is_fastpath) { 14311cb0ef41Sopenharmony_ci // Must be in Smi range on the fast path. We control the value of {index} 14321cb0ef41Sopenharmony_ci // on all call-sites and can never exceed the length of the string. 14331cb0ef41Sopenharmony_ci STATIC_ASSERT(String::kMaxLength + 2 < Smi::kMaxValue); 14341cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsPositiveSmi(index_plus_one)); 14351cb0ef41Sopenharmony_ci } 14361cb0ef41Sopenharmony_ci 14371cb0ef41Sopenharmony_ci Label if_isunicode(this), out(this); 14381cb0ef41Sopenharmony_ci GotoIfNot(is_unicode, &out); 14391cb0ef41Sopenharmony_ci 14401cb0ef41Sopenharmony_ci // Keep this unconditional (even on the fast path) just to be safe. 14411cb0ef41Sopenharmony_ci Branch(TaggedIsPositiveSmi(index_plus_one), &if_isunicode, &out); 14421cb0ef41Sopenharmony_ci 14431cb0ef41Sopenharmony_ci BIND(&if_isunicode); 14441cb0ef41Sopenharmony_ci { 14451cb0ef41Sopenharmony_ci TNode<UintPtrT> string_length = Unsigned(LoadStringLengthAsWord(string)); 14461cb0ef41Sopenharmony_ci TNode<UintPtrT> untagged_plus_one = 14471cb0ef41Sopenharmony_ci Unsigned(SmiUntag(CAST(index_plus_one))); 14481cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(untagged_plus_one, string_length), &out); 14491cb0ef41Sopenharmony_ci 14501cb0ef41Sopenharmony_ci TNode<Int32T> lead = 14511cb0ef41Sopenharmony_ci StringCharCodeAt(string, Unsigned(SmiUntag(CAST(index)))); 14521cb0ef41Sopenharmony_ci GotoIfNot(Word32Equal(Word32And(lead, Int32Constant(0xFC00)), 14531cb0ef41Sopenharmony_ci Int32Constant(0xD800)), 14541cb0ef41Sopenharmony_ci &out); 14551cb0ef41Sopenharmony_ci 14561cb0ef41Sopenharmony_ci TNode<Int32T> trail = StringCharCodeAt(string, untagged_plus_one); 14571cb0ef41Sopenharmony_ci GotoIfNot(Word32Equal(Word32And(trail, Int32Constant(0xFC00)), 14581cb0ef41Sopenharmony_ci Int32Constant(0xDC00)), 14591cb0ef41Sopenharmony_ci &out); 14601cb0ef41Sopenharmony_ci 14611cb0ef41Sopenharmony_ci // At a surrogate pair, return index + 2. 14621cb0ef41Sopenharmony_ci TNode<Number> index_plus_two = NumberInc(index_plus_one); 14631cb0ef41Sopenharmony_ci var_result = index_plus_two; 14641cb0ef41Sopenharmony_ci 14651cb0ef41Sopenharmony_ci Goto(&out); 14661cb0ef41Sopenharmony_ci } 14671cb0ef41Sopenharmony_ci 14681cb0ef41Sopenharmony_ci BIND(&out); 14691cb0ef41Sopenharmony_ci return var_result.value(); 14701cb0ef41Sopenharmony_ci} 14711cb0ef41Sopenharmony_ci 14721cb0ef41Sopenharmony_ci// ES#sec-createregexpstringiterator 14731cb0ef41Sopenharmony_ci// CreateRegExpStringIterator ( R, S, global, fullUnicode ) 14741cb0ef41Sopenharmony_ciTNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator( 14751cb0ef41Sopenharmony_ci TNode<NativeContext> native_context, TNode<Object> regexp, 14761cb0ef41Sopenharmony_ci TNode<String> string, TNode<BoolT> global, TNode<BoolT> full_unicode) { 14771cb0ef41Sopenharmony_ci TNode<Map> map = CAST(LoadContextElement( 14781cb0ef41Sopenharmony_ci native_context, 14791cb0ef41Sopenharmony_ci Context::INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX)); 14801cb0ef41Sopenharmony_ci 14811cb0ef41Sopenharmony_ci // 4. Let iterator be ObjectCreate(%RegExpStringIteratorPrototype%, « 14821cb0ef41Sopenharmony_ci // [[IteratingRegExp]], [[IteratedString]], [[Global]], [[Unicode]], 14831cb0ef41Sopenharmony_ci // [[Done]] »). 14841cb0ef41Sopenharmony_ci TNode<HeapObject> iterator = Allocate(JSRegExpStringIterator::kHeaderSize); 14851cb0ef41Sopenharmony_ci StoreMapNoWriteBarrier(iterator, map); 14861cb0ef41Sopenharmony_ci StoreObjectFieldRoot(iterator, 14871cb0ef41Sopenharmony_ci JSRegExpStringIterator::kPropertiesOrHashOffset, 14881cb0ef41Sopenharmony_ci RootIndex::kEmptyFixedArray); 14891cb0ef41Sopenharmony_ci StoreObjectFieldRoot(iterator, JSRegExpStringIterator::kElementsOffset, 14901cb0ef41Sopenharmony_ci RootIndex::kEmptyFixedArray); 14911cb0ef41Sopenharmony_ci 14921cb0ef41Sopenharmony_ci // 5. Set iterator.[[IteratingRegExp]] to R. 14931cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 14941cb0ef41Sopenharmony_ci iterator, JSRegExpStringIterator::kIteratingRegExpOffset, regexp); 14951cb0ef41Sopenharmony_ci 14961cb0ef41Sopenharmony_ci // 6. Set iterator.[[IteratedString]] to S. 14971cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 14981cb0ef41Sopenharmony_ci iterator, JSRegExpStringIterator::kIteratedStringOffset, string); 14991cb0ef41Sopenharmony_ci 15001cb0ef41Sopenharmony_ci // 7. Set iterator.[[Global]] to global. 15011cb0ef41Sopenharmony_ci // 8. Set iterator.[[Unicode]] to fullUnicode. 15021cb0ef41Sopenharmony_ci // 9. Set iterator.[[Done]] to false. 15031cb0ef41Sopenharmony_ci TNode<Int32T> global_flag = 15041cb0ef41Sopenharmony_ci Word32Shl(ReinterpretCast<Int32T>(global), 15051cb0ef41Sopenharmony_ci Int32Constant(JSRegExpStringIterator::GlobalBit::kShift)); 15061cb0ef41Sopenharmony_ci TNode<Int32T> unicode_flag = 15071cb0ef41Sopenharmony_ci Word32Shl(ReinterpretCast<Int32T>(full_unicode), 15081cb0ef41Sopenharmony_ci Int32Constant(JSRegExpStringIterator::UnicodeBit::kShift)); 15091cb0ef41Sopenharmony_ci TNode<Int32T> iterator_flags = Word32Or(global_flag, unicode_flag); 15101cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(iterator, JSRegExpStringIterator::kFlagsOffset, 15111cb0ef41Sopenharmony_ci SmiFromInt32(iterator_flags)); 15121cb0ef41Sopenharmony_ci 15131cb0ef41Sopenharmony_ci return iterator; 15141cb0ef41Sopenharmony_ci} 15151cb0ef41Sopenharmony_ci 15161cb0ef41Sopenharmony_ci// Generates the fast path for @@split. {regexp} is an unmodified, non-sticky 15171cb0ef41Sopenharmony_ci// JSRegExp, {string} is a String, and {limit} is a Smi. 15181cb0ef41Sopenharmony_ciTNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( 15191cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string, 15201cb0ef41Sopenharmony_ci const TNode<Smi> limit) { 15211cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsFastRegExpPermissive(context, regexp)); 15221cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32BinaryNot(FastFlagGetter(regexp, JSRegExp::kSticky))); 15231cb0ef41Sopenharmony_ci 15241cb0ef41Sopenharmony_ci const TNode<IntPtrT> int_limit = SmiUntag(limit); 15251cb0ef41Sopenharmony_ci 15261cb0ef41Sopenharmony_ci const ElementsKind kind = PACKED_ELEMENTS; 15271cb0ef41Sopenharmony_ci 15281cb0ef41Sopenharmony_ci const TNode<NativeContext> native_context = LoadNativeContext(context); 15291cb0ef41Sopenharmony_ci TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); 15301cb0ef41Sopenharmony_ci 15311cb0ef41Sopenharmony_ci Label return_empty_array(this, Label::kDeferred); 15321cb0ef41Sopenharmony_ci TVARIABLE(JSArray, var_result); 15331cb0ef41Sopenharmony_ci Label done(this); 15341cb0ef41Sopenharmony_ci 15351cb0ef41Sopenharmony_ci // If limit is zero, return an empty array. 15361cb0ef41Sopenharmony_ci { 15371cb0ef41Sopenharmony_ci Label next(this), if_limitiszero(this, Label::kDeferred); 15381cb0ef41Sopenharmony_ci Branch(SmiEqual(limit, SmiZero()), &return_empty_array, &next); 15391cb0ef41Sopenharmony_ci BIND(&next); 15401cb0ef41Sopenharmony_ci } 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_ci const TNode<Smi> string_length = LoadStringLengthAsSmi(string); 15431cb0ef41Sopenharmony_ci 15441cb0ef41Sopenharmony_ci // If passed the empty {string}, return either an empty array or a singleton 15451cb0ef41Sopenharmony_ci // array depending on whether the {regexp} matches. 15461cb0ef41Sopenharmony_ci { 15471cb0ef41Sopenharmony_ci Label next(this), if_stringisempty(this, Label::kDeferred); 15481cb0ef41Sopenharmony_ci Branch(SmiEqual(string_length, SmiZero()), &if_stringisempty, &next); 15491cb0ef41Sopenharmony_ci 15501cb0ef41Sopenharmony_ci BIND(&if_stringisempty); 15511cb0ef41Sopenharmony_ci { 15521cb0ef41Sopenharmony_ci const TNode<Object> last_match_info = LoadContextElement( 15531cb0ef41Sopenharmony_ci native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 15541cb0ef41Sopenharmony_ci 15551cb0ef41Sopenharmony_ci const TNode<Object> match_indices = 15561cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kRegExpExecInternal, context, regexp, string, 15571cb0ef41Sopenharmony_ci SmiZero(), last_match_info); 15581cb0ef41Sopenharmony_ci 15591cb0ef41Sopenharmony_ci Label return_singleton_array(this); 15601cb0ef41Sopenharmony_ci Branch(IsNull(match_indices), &return_singleton_array, 15611cb0ef41Sopenharmony_ci &return_empty_array); 15621cb0ef41Sopenharmony_ci 15631cb0ef41Sopenharmony_ci BIND(&return_singleton_array); 15641cb0ef41Sopenharmony_ci { 15651cb0ef41Sopenharmony_ci TNode<Smi> length = SmiConstant(1); 15661cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = IntPtrConstant(1); 15671cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt; 15681cb0ef41Sopenharmony_ci var_result = 15691cb0ef41Sopenharmony_ci AllocateJSArray(kind, array_map, capacity, length, allocation_site); 15701cb0ef41Sopenharmony_ci 15711cb0ef41Sopenharmony_ci TNode<FixedArray> fixed_array = CAST(LoadElements(var_result.value())); 15721cb0ef41Sopenharmony_ci UnsafeStoreFixedArrayElement(fixed_array, 0, string); 15731cb0ef41Sopenharmony_ci 15741cb0ef41Sopenharmony_ci Goto(&done); 15751cb0ef41Sopenharmony_ci } 15761cb0ef41Sopenharmony_ci } 15771cb0ef41Sopenharmony_ci 15781cb0ef41Sopenharmony_ci BIND(&next); 15791cb0ef41Sopenharmony_ci } 15801cb0ef41Sopenharmony_ci 15811cb0ef41Sopenharmony_ci // Loop preparations. 15821cb0ef41Sopenharmony_ci 15831cb0ef41Sopenharmony_ci GrowableFixedArray array(state()); 15841cb0ef41Sopenharmony_ci 15851cb0ef41Sopenharmony_ci TVARIABLE(Smi, var_last_matched_until, SmiZero()); 15861cb0ef41Sopenharmony_ci TVARIABLE(Smi, var_next_search_from, SmiZero()); 15871cb0ef41Sopenharmony_ci 15881cb0ef41Sopenharmony_ci Label loop(this, {array.var_array(), array.var_length(), array.var_capacity(), 15891cb0ef41Sopenharmony_ci &var_last_matched_until, &var_next_search_from}), 15901cb0ef41Sopenharmony_ci push_suffix_and_out(this), out(this); 15911cb0ef41Sopenharmony_ci Goto(&loop); 15921cb0ef41Sopenharmony_ci 15931cb0ef41Sopenharmony_ci BIND(&loop); 15941cb0ef41Sopenharmony_ci { 15951cb0ef41Sopenharmony_ci const TNode<Smi> next_search_from = var_next_search_from.value(); 15961cb0ef41Sopenharmony_ci const TNode<Smi> last_matched_until = var_last_matched_until.value(); 15971cb0ef41Sopenharmony_ci 15981cb0ef41Sopenharmony_ci // We're done if we've reached the end of the string. 15991cb0ef41Sopenharmony_ci { 16001cb0ef41Sopenharmony_ci Label next(this); 16011cb0ef41Sopenharmony_ci Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out, 16021cb0ef41Sopenharmony_ci &next); 16031cb0ef41Sopenharmony_ci BIND(&next); 16041cb0ef41Sopenharmony_ci } 16051cb0ef41Sopenharmony_ci 16061cb0ef41Sopenharmony_ci // Search for the given {regexp}. 16071cb0ef41Sopenharmony_ci 16081cb0ef41Sopenharmony_ci const TNode<Object> last_match_info = LoadContextElement( 16091cb0ef41Sopenharmony_ci native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 16101cb0ef41Sopenharmony_ci 16111cb0ef41Sopenharmony_ci const TNode<HeapObject> match_indices_ho = RegExpExecInternal( 16121cb0ef41Sopenharmony_ci context, regexp, string, next_search_from, CAST(last_match_info), 16131cb0ef41Sopenharmony_ci RegExp::ExecQuirks::kTreatMatchAtEndAsFailure); 16141cb0ef41Sopenharmony_ci 16151cb0ef41Sopenharmony_ci // We're done if no match was found. 16161cb0ef41Sopenharmony_ci { 16171cb0ef41Sopenharmony_ci Label next(this); 16181cb0ef41Sopenharmony_ci Branch(IsNull(match_indices_ho), &push_suffix_and_out, &next); 16191cb0ef41Sopenharmony_ci BIND(&next); 16201cb0ef41Sopenharmony_ci } 16211cb0ef41Sopenharmony_ci 16221cb0ef41Sopenharmony_ci TNode<FixedArray> match_indices = CAST(match_indices_ho); 16231cb0ef41Sopenharmony_ci const TNode<Smi> match_from = CAST(UnsafeLoadFixedArrayElement( 16241cb0ef41Sopenharmony_ci match_indices, RegExpMatchInfo::kFirstCaptureIndex)); 16251cb0ef41Sopenharmony_ci const TNode<Smi> match_to = CAST(UnsafeLoadFixedArrayElement( 16261cb0ef41Sopenharmony_ci match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1)); 16271cb0ef41Sopenharmony_ci CSA_DCHECK(this, SmiNotEqual(match_from, string_length)); 16281cb0ef41Sopenharmony_ci 16291cb0ef41Sopenharmony_ci // Advance index and continue if the match is empty. 16301cb0ef41Sopenharmony_ci { 16311cb0ef41Sopenharmony_ci Label next(this); 16321cb0ef41Sopenharmony_ci 16331cb0ef41Sopenharmony_ci GotoIfNot(SmiEqual(match_to, next_search_from), &next); 16341cb0ef41Sopenharmony_ci GotoIfNot(SmiEqual(match_to, last_matched_until), &next); 16351cb0ef41Sopenharmony_ci 16361cb0ef41Sopenharmony_ci const TNode<BoolT> is_unicode = 16371cb0ef41Sopenharmony_ci FastFlagGetter(regexp, JSRegExp::kUnicode); 16381cb0ef41Sopenharmony_ci const TNode<Number> new_next_search_from = 16391cb0ef41Sopenharmony_ci AdvanceStringIndex(string, next_search_from, is_unicode, true); 16401cb0ef41Sopenharmony_ci var_next_search_from = CAST(new_next_search_from); 16411cb0ef41Sopenharmony_ci Goto(&loop); 16421cb0ef41Sopenharmony_ci 16431cb0ef41Sopenharmony_ci BIND(&next); 16441cb0ef41Sopenharmony_ci } 16451cb0ef41Sopenharmony_ci 16461cb0ef41Sopenharmony_ci // A valid match was found, add the new substring to the array. 16471cb0ef41Sopenharmony_ci { 16481cb0ef41Sopenharmony_ci const TNode<Smi> from = last_matched_until; 16491cb0ef41Sopenharmony_ci const TNode<Smi> to = match_from; 16501cb0ef41Sopenharmony_ci array.Push(CallBuiltin(Builtin::kSubString, context, string, from, to)); 16511cb0ef41Sopenharmony_ci GotoIf(WordEqual(array.length(), int_limit), &out); 16521cb0ef41Sopenharmony_ci } 16531cb0ef41Sopenharmony_ci 16541cb0ef41Sopenharmony_ci // Add all captures to the array. 16551cb0ef41Sopenharmony_ci { 16561cb0ef41Sopenharmony_ci const TNode<Smi> num_registers = CAST(LoadFixedArrayElement( 16571cb0ef41Sopenharmony_ci match_indices, RegExpMatchInfo::kNumberOfCapturesIndex)); 16581cb0ef41Sopenharmony_ci const TNode<IntPtrT> int_num_registers = SmiUntag(num_registers); 16591cb0ef41Sopenharmony_ci 16601cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, var_reg, IntPtrConstant(2)); 16611cb0ef41Sopenharmony_ci 16621cb0ef41Sopenharmony_ci Label nested_loop(this, {array.var_array(), array.var_length(), 16631cb0ef41Sopenharmony_ci array.var_capacity(), &var_reg}), 16641cb0ef41Sopenharmony_ci nested_loop_out(this); 16651cb0ef41Sopenharmony_ci Branch(IntPtrLessThan(var_reg.value(), int_num_registers), &nested_loop, 16661cb0ef41Sopenharmony_ci &nested_loop_out); 16671cb0ef41Sopenharmony_ci 16681cb0ef41Sopenharmony_ci BIND(&nested_loop); 16691cb0ef41Sopenharmony_ci { 16701cb0ef41Sopenharmony_ci const TNode<IntPtrT> reg = var_reg.value(); 16711cb0ef41Sopenharmony_ci const TNode<Object> from = LoadFixedArrayElement( 16721cb0ef41Sopenharmony_ci match_indices, reg, 16731cb0ef41Sopenharmony_ci RegExpMatchInfo::kFirstCaptureIndex * kTaggedSize); 16741cb0ef41Sopenharmony_ci const TNode<Smi> to = CAST(LoadFixedArrayElement( 16751cb0ef41Sopenharmony_ci match_indices, reg, 16761cb0ef41Sopenharmony_ci (RegExpMatchInfo::kFirstCaptureIndex + 1) * kTaggedSize)); 16771cb0ef41Sopenharmony_ci 16781cb0ef41Sopenharmony_ci Label select_capture(this), select_undefined(this), store_value(this); 16791cb0ef41Sopenharmony_ci TVARIABLE(Object, var_value); 16801cb0ef41Sopenharmony_ci Branch(SmiEqual(to, SmiConstant(-1)), &select_undefined, 16811cb0ef41Sopenharmony_ci &select_capture); 16821cb0ef41Sopenharmony_ci 16831cb0ef41Sopenharmony_ci BIND(&select_capture); 16841cb0ef41Sopenharmony_ci { 16851cb0ef41Sopenharmony_ci var_value = 16861cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kSubString, context, string, from, to); 16871cb0ef41Sopenharmony_ci Goto(&store_value); 16881cb0ef41Sopenharmony_ci } 16891cb0ef41Sopenharmony_ci 16901cb0ef41Sopenharmony_ci BIND(&select_undefined); 16911cb0ef41Sopenharmony_ci { 16921cb0ef41Sopenharmony_ci var_value = UndefinedConstant(); 16931cb0ef41Sopenharmony_ci Goto(&store_value); 16941cb0ef41Sopenharmony_ci } 16951cb0ef41Sopenharmony_ci 16961cb0ef41Sopenharmony_ci BIND(&store_value); 16971cb0ef41Sopenharmony_ci { 16981cb0ef41Sopenharmony_ci array.Push(var_value.value()); 16991cb0ef41Sopenharmony_ci GotoIf(WordEqual(array.length(), int_limit), &out); 17001cb0ef41Sopenharmony_ci 17011cb0ef41Sopenharmony_ci const TNode<IntPtrT> new_reg = IntPtrAdd(reg, IntPtrConstant(2)); 17021cb0ef41Sopenharmony_ci var_reg = new_reg; 17031cb0ef41Sopenharmony_ci 17041cb0ef41Sopenharmony_ci Branch(IntPtrLessThan(new_reg, int_num_registers), &nested_loop, 17051cb0ef41Sopenharmony_ci &nested_loop_out); 17061cb0ef41Sopenharmony_ci } 17071cb0ef41Sopenharmony_ci } 17081cb0ef41Sopenharmony_ci 17091cb0ef41Sopenharmony_ci BIND(&nested_loop_out); 17101cb0ef41Sopenharmony_ci } 17111cb0ef41Sopenharmony_ci 17121cb0ef41Sopenharmony_ci var_last_matched_until = match_to; 17131cb0ef41Sopenharmony_ci var_next_search_from = match_to; 17141cb0ef41Sopenharmony_ci Goto(&loop); 17151cb0ef41Sopenharmony_ci } 17161cb0ef41Sopenharmony_ci 17171cb0ef41Sopenharmony_ci BIND(&push_suffix_and_out); 17181cb0ef41Sopenharmony_ci { 17191cb0ef41Sopenharmony_ci const TNode<Smi> from = var_last_matched_until.value(); 17201cb0ef41Sopenharmony_ci const TNode<Smi> to = string_length; 17211cb0ef41Sopenharmony_ci array.Push(CallBuiltin(Builtin::kSubString, context, string, from, to)); 17221cb0ef41Sopenharmony_ci Goto(&out); 17231cb0ef41Sopenharmony_ci } 17241cb0ef41Sopenharmony_ci 17251cb0ef41Sopenharmony_ci BIND(&out); 17261cb0ef41Sopenharmony_ci { 17271cb0ef41Sopenharmony_ci var_result = array.ToJSArray(context); 17281cb0ef41Sopenharmony_ci Goto(&done); 17291cb0ef41Sopenharmony_ci } 17301cb0ef41Sopenharmony_ci 17311cb0ef41Sopenharmony_ci BIND(&return_empty_array); 17321cb0ef41Sopenharmony_ci { 17331cb0ef41Sopenharmony_ci TNode<Smi> length = SmiZero(); 17341cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = IntPtrZero(); 17351cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt; 17361cb0ef41Sopenharmony_ci var_result = 17371cb0ef41Sopenharmony_ci AllocateJSArray(kind, array_map, capacity, length, allocation_site); 17381cb0ef41Sopenharmony_ci Goto(&done); 17391cb0ef41Sopenharmony_ci } 17401cb0ef41Sopenharmony_ci 17411cb0ef41Sopenharmony_ci BIND(&done); 17421cb0ef41Sopenharmony_ci return var_result.value(); 17431cb0ef41Sopenharmony_ci} 17441cb0ef41Sopenharmony_ci 17451cb0ef41Sopenharmony_ci} // namespace internal 17461cb0ef41Sopenharmony_ci} // namespace v8 1747