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