11cb0ef41Sopenharmony_ci// Copyright 2020 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/regexp/experimental/experimental.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
81cb0ef41Sopenharmony_ci#include "src/objects/js-regexp-inl.h"
91cb0ef41Sopenharmony_ci#include "src/regexp/experimental/experimental-compiler.h"
101cb0ef41Sopenharmony_ci#include "src/regexp/experimental/experimental-interpreter.h"
111cb0ef41Sopenharmony_ci#include "src/regexp/regexp-parser.h"
121cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cibool ExperimentalRegExp::CanBeHandled(RegExpTree* tree, RegExpFlags flags,
181cb0ef41Sopenharmony_ci                                      int capture_count) {
191cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine ||
201cb0ef41Sopenharmony_ci         FLAG_enable_experimental_regexp_engine_on_excessive_backtracks);
211cb0ef41Sopenharmony_ci  return ExperimentalRegExpCompiler::CanBeHandled(tree, flags, capture_count);
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_civoid ExperimentalRegExp::Initialize(Isolate* isolate, Handle<JSRegExp> re,
251cb0ef41Sopenharmony_ci                                    Handle<String> source, RegExpFlags flags,
261cb0ef41Sopenharmony_ci                                    int capture_count) {
271cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
281cb0ef41Sopenharmony_ci  if (FLAG_trace_experimental_regexp_engine) {
291cb0ef41Sopenharmony_ci    StdoutStream{} << "Initializing experimental regexp " << *source
301cb0ef41Sopenharmony_ci                   << std::endl;
311cb0ef41Sopenharmony_ci  }
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  isolate->factory()->SetRegExpExperimentalData(
341cb0ef41Sopenharmony_ci      re, source, JSRegExp::AsJSRegExpFlags(flags), capture_count);
351cb0ef41Sopenharmony_ci}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_cibool ExperimentalRegExp::IsCompiled(Handle<JSRegExp> re, Isolate* isolate) {
381cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
391cb0ef41Sopenharmony_ci  DCHECK_EQ(re->type_tag(), JSRegExp::EXPERIMENTAL);
401cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP
411cb0ef41Sopenharmony_ci  re->JSRegExpVerify(isolate);
421cb0ef41Sopenharmony_ci#endif
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  static constexpr bool kIsLatin1 = true;
451cb0ef41Sopenharmony_ci  return re->bytecode(kIsLatin1) != Smi::FromInt(JSRegExp::kUninitializedValue);
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_citemplate <class T>
491cb0ef41Sopenharmony_ciHandle<ByteArray> VectorToByteArray(Isolate* isolate, base::Vector<T> data) {
501cb0ef41Sopenharmony_ci  STATIC_ASSERT(std::is_trivial<T>::value);
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  int byte_length = sizeof(T) * data.length();
531cb0ef41Sopenharmony_ci  Handle<ByteArray> byte_array = isolate->factory()->NewByteArray(byte_length);
541cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
551cb0ef41Sopenharmony_ci  MemCopy(byte_array->GetDataStartAddress(), data.begin(), byte_length);
561cb0ef41Sopenharmony_ci  return byte_array;
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_cinamespace {
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_cistruct CompilationResult {
621cb0ef41Sopenharmony_ci  Handle<ByteArray> bytecode;
631cb0ef41Sopenharmony_ci  Handle<FixedArray> capture_name_map;
641cb0ef41Sopenharmony_ci};
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci// Compiles source pattern, but doesn't change the regexp object.
671cb0ef41Sopenharmony_cibase::Optional<CompilationResult> CompileImpl(Isolate* isolate,
681cb0ef41Sopenharmony_ci                                              Handle<JSRegExp> regexp) {
691cb0ef41Sopenharmony_ci  Zone zone(isolate->allocator(), ZONE_NAME);
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  Handle<String> source(regexp->source(), isolate);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  // Parse and compile the regexp source.
741cb0ef41Sopenharmony_ci  RegExpCompileData parse_result;
751cb0ef41Sopenharmony_ci  DCHECK(!isolate->has_pending_exception());
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  bool parse_success = RegExpParser::ParseRegExpFromHeapString(
781cb0ef41Sopenharmony_ci      isolate, &zone, source, JSRegExp::AsRegExpFlags(regexp->flags()),
791cb0ef41Sopenharmony_ci      &parse_result);
801cb0ef41Sopenharmony_ci  if (!parse_success) {
811cb0ef41Sopenharmony_ci    // The pattern was already parsed successfully during initialization, so
821cb0ef41Sopenharmony_ci    // the only way parsing can fail now is because of stack overflow.
831cb0ef41Sopenharmony_ci    DCHECK_EQ(parse_result.error, RegExpError::kStackOverflow);
841cb0ef41Sopenharmony_ci    USE(RegExp::ThrowRegExpException(isolate, regexp, source,
851cb0ef41Sopenharmony_ci                                     parse_result.error));
861cb0ef41Sopenharmony_ci    return base::nullopt;
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  ZoneList<RegExpInstruction> bytecode = ExperimentalRegExpCompiler::Compile(
901cb0ef41Sopenharmony_ci      parse_result.tree, JSRegExp::AsRegExpFlags(regexp->flags()), &zone);
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  CompilationResult result;
931cb0ef41Sopenharmony_ci  result.bytecode = VectorToByteArray(isolate, bytecode.ToVector());
941cb0ef41Sopenharmony_ci  result.capture_name_map =
951cb0ef41Sopenharmony_ci      RegExp::CreateCaptureNameMap(isolate, parse_result.named_captures);
961cb0ef41Sopenharmony_ci  return result;
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci}  // namespace
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_cibool ExperimentalRegExp::Compile(Isolate* isolate, Handle<JSRegExp> re) {
1021cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
1031cb0ef41Sopenharmony_ci  DCHECK_EQ(re->type_tag(), JSRegExp::EXPERIMENTAL);
1041cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP
1051cb0ef41Sopenharmony_ci  re->JSRegExpVerify(isolate);
1061cb0ef41Sopenharmony_ci#endif
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  Handle<String> source(re->source(), isolate);
1091cb0ef41Sopenharmony_ci  if (FLAG_trace_experimental_regexp_engine) {
1101cb0ef41Sopenharmony_ci    StdoutStream{} << "Compiling experimental regexp " << *source << std::endl;
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  base::Optional<CompilationResult> compilation_result =
1141cb0ef41Sopenharmony_ci      CompileImpl(isolate, re);
1151cb0ef41Sopenharmony_ci  if (!compilation_result.has_value()) {
1161cb0ef41Sopenharmony_ci    DCHECK(isolate->has_pending_exception());
1171cb0ef41Sopenharmony_ci    return false;
1181cb0ef41Sopenharmony_ci  }
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  re->set_bytecode_and_trampoline(isolate, compilation_result->bytecode);
1211cb0ef41Sopenharmony_ci  re->set_capture_name_map(compilation_result->capture_name_map);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  return true;
1241cb0ef41Sopenharmony_ci}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_cibase::Vector<RegExpInstruction> AsInstructionSequence(ByteArray raw_bytes) {
1271cb0ef41Sopenharmony_ci  RegExpInstruction* inst_begin =
1281cb0ef41Sopenharmony_ci      reinterpret_cast<RegExpInstruction*>(raw_bytes.GetDataStartAddress());
1291cb0ef41Sopenharmony_ci  int inst_num = raw_bytes.length() / sizeof(RegExpInstruction);
1301cb0ef41Sopenharmony_ci  DCHECK_EQ(sizeof(RegExpInstruction) * inst_num, raw_bytes.length());
1311cb0ef41Sopenharmony_ci  return base::Vector<RegExpInstruction>(inst_begin, inst_num);
1321cb0ef41Sopenharmony_ci}
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_cinamespace {
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ciint32_t ExecRawImpl(Isolate* isolate, RegExp::CallOrigin call_origin,
1371cb0ef41Sopenharmony_ci                    ByteArray bytecode, String subject, int capture_count,
1381cb0ef41Sopenharmony_ci                    int32_t* output_registers, int32_t output_register_count,
1391cb0ef41Sopenharmony_ci                    int32_t subject_index) {
1401cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
1411cb0ef41Sopenharmony_ci  // TODO(cbruni): remove once gcmole is fixed.
1421cb0ef41Sopenharmony_ci  DisableGCMole no_gc_mole;
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  int register_count_per_match =
1451cb0ef41Sopenharmony_ci      JSRegExp::RegistersForCaptureCount(capture_count);
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  int32_t result;
1481cb0ef41Sopenharmony_ci  do {
1491cb0ef41Sopenharmony_ci    DCHECK(subject.IsFlat());
1501cb0ef41Sopenharmony_ci    Zone zone(isolate->allocator(), ZONE_NAME);
1511cb0ef41Sopenharmony_ci    result = ExperimentalRegExpInterpreter::FindMatches(
1521cb0ef41Sopenharmony_ci        isolate, call_origin, bytecode, register_count_per_match, subject,
1531cb0ef41Sopenharmony_ci        subject_index, output_registers, output_register_count, &zone);
1541cb0ef41Sopenharmony_ci  } while (result == RegExp::kInternalRegExpRetry &&
1551cb0ef41Sopenharmony_ci           call_origin == RegExp::kFromRuntime);
1561cb0ef41Sopenharmony_ci  return result;
1571cb0ef41Sopenharmony_ci}
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci}  // namespace
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci// Returns the number of matches.
1621cb0ef41Sopenharmony_ciint32_t ExperimentalRegExp::ExecRaw(Isolate* isolate,
1631cb0ef41Sopenharmony_ci                                    RegExp::CallOrigin call_origin,
1641cb0ef41Sopenharmony_ci                                    JSRegExp regexp, String subject,
1651cb0ef41Sopenharmony_ci                                    int32_t* output_registers,
1661cb0ef41Sopenharmony_ci                                    int32_t output_register_count,
1671cb0ef41Sopenharmony_ci                                    int32_t subject_index) {
1681cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
1691cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  if (FLAG_trace_experimental_regexp_engine) {
1721cb0ef41Sopenharmony_ci    StdoutStream{} << "Executing experimental regexp " << regexp.source()
1731cb0ef41Sopenharmony_ci                   << std::endl;
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  static constexpr bool kIsLatin1 = true;
1771cb0ef41Sopenharmony_ci  ByteArray bytecode = ByteArray::cast(regexp.bytecode(kIsLatin1));
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  return ExecRawImpl(isolate, call_origin, bytecode, subject,
1801cb0ef41Sopenharmony_ci                     regexp.capture_count(), output_registers,
1811cb0ef41Sopenharmony_ci                     output_register_count, subject_index);
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ciint32_t ExperimentalRegExp::MatchForCallFromJs(
1851cb0ef41Sopenharmony_ci    Address subject, int32_t start_position, Address input_start,
1861cb0ef41Sopenharmony_ci    Address input_end, int* output_registers, int32_t output_register_count,
1871cb0ef41Sopenharmony_ci    RegExp::CallOrigin call_origin, Isolate* isolate, Address regexp) {
1881cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
1891cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(isolate);
1901cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(output_registers);
1911cb0ef41Sopenharmony_ci  DCHECK(call_origin == RegExp::CallOrigin::kFromJs);
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
1941cb0ef41Sopenharmony_ci  DisallowJavascriptExecution no_js(isolate);
1951cb0ef41Sopenharmony_ci  DisallowHandleAllocation no_handles;
1961cb0ef41Sopenharmony_ci  DisallowHandleDereference no_deref;
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  String subject_string = String::cast(Object(subject));
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  JSRegExp regexp_obj = JSRegExp::cast(Object(regexp));
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  return ExecRaw(isolate, RegExp::kFromJs, regexp_obj, subject_string,
2031cb0ef41Sopenharmony_ci                 output_registers, output_register_count, start_position);
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ciMaybeHandle<Object> ExperimentalRegExp::Exec(
2071cb0ef41Sopenharmony_ci    Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject,
2081cb0ef41Sopenharmony_ci    int subject_index, Handle<RegExpMatchInfo> last_match_info,
2091cb0ef41Sopenharmony_ci    RegExp::ExecQuirks exec_quirks) {
2101cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine);
2111cb0ef41Sopenharmony_ci  DCHECK_EQ(regexp->type_tag(), JSRegExp::EXPERIMENTAL);
2121cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP
2131cb0ef41Sopenharmony_ci  regexp->JSRegExpVerify(isolate);
2141cb0ef41Sopenharmony_ci#endif
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  if (!IsCompiled(regexp, isolate) && !Compile(isolate, regexp)) {
2171cb0ef41Sopenharmony_ci    DCHECK(isolate->has_pending_exception());
2181cb0ef41Sopenharmony_ci    return MaybeHandle<Object>();
2191cb0ef41Sopenharmony_ci  }
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  DCHECK(IsCompiled(regexp, isolate));
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci  subject = String::Flatten(isolate, subject);
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  int capture_count = regexp->capture_count();
2261cb0ef41Sopenharmony_ci  int output_register_count = JSRegExp::RegistersForCaptureCount(capture_count);
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  int32_t* output_registers;
2291cb0ef41Sopenharmony_ci  std::unique_ptr<int32_t[]> output_registers_release;
2301cb0ef41Sopenharmony_ci  if (output_register_count <= Isolate::kJSRegexpStaticOffsetsVectorSize) {
2311cb0ef41Sopenharmony_ci    output_registers = isolate->jsregexp_static_offsets_vector();
2321cb0ef41Sopenharmony_ci  } else {
2331cb0ef41Sopenharmony_ci    output_registers = NewArray<int32_t>(output_register_count);
2341cb0ef41Sopenharmony_ci    output_registers_release.reset(output_registers);
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  int num_matches =
2381cb0ef41Sopenharmony_ci      ExecRaw(isolate, RegExp::kFromRuntime, *regexp, *subject,
2391cb0ef41Sopenharmony_ci              output_registers, output_register_count, subject_index);
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if (num_matches > 0) {
2421cb0ef41Sopenharmony_ci    DCHECK_EQ(num_matches, 1);
2431cb0ef41Sopenharmony_ci    if (exec_quirks == RegExp::ExecQuirks::kTreatMatchAtEndAsFailure) {
2441cb0ef41Sopenharmony_ci      if (output_registers[0] >= subject->length()) {
2451cb0ef41Sopenharmony_ci        return isolate->factory()->null_value();
2461cb0ef41Sopenharmony_ci      }
2471cb0ef41Sopenharmony_ci    }
2481cb0ef41Sopenharmony_ci    return RegExp::SetLastMatchInfo(isolate, last_match_info, subject,
2491cb0ef41Sopenharmony_ci                                    capture_count, output_registers);
2501cb0ef41Sopenharmony_ci  } else if (num_matches == 0) {
2511cb0ef41Sopenharmony_ci    return isolate->factory()->null_value();
2521cb0ef41Sopenharmony_ci  } else {
2531cb0ef41Sopenharmony_ci    DCHECK_LT(num_matches, 0);
2541cb0ef41Sopenharmony_ci    DCHECK(isolate->has_pending_exception());
2551cb0ef41Sopenharmony_ci    return MaybeHandle<Object>();
2561cb0ef41Sopenharmony_ci  }
2571cb0ef41Sopenharmony_ci}
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ciint32_t ExperimentalRegExp::OneshotExecRaw(Isolate* isolate,
2601cb0ef41Sopenharmony_ci                                           Handle<JSRegExp> regexp,
2611cb0ef41Sopenharmony_ci                                           Handle<String> subject,
2621cb0ef41Sopenharmony_ci                                           int32_t* output_registers,
2631cb0ef41Sopenharmony_ci                                           int32_t output_register_count,
2641cb0ef41Sopenharmony_ci                                           int32_t subject_index) {
2651cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine_on_excessive_backtracks);
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci  if (FLAG_trace_experimental_regexp_engine) {
2681cb0ef41Sopenharmony_ci    StdoutStream{} << "Experimental execution (oneshot) of regexp "
2691cb0ef41Sopenharmony_ci                   << regexp->source() << std::endl;
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  base::Optional<CompilationResult> compilation_result =
2731cb0ef41Sopenharmony_ci      CompileImpl(isolate, regexp);
2741cb0ef41Sopenharmony_ci  if (!compilation_result.has_value()) return RegExp::kInternalRegExpException;
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
2771cb0ef41Sopenharmony_ci  return ExecRawImpl(isolate, RegExp::kFromRuntime,
2781cb0ef41Sopenharmony_ci                     *compilation_result->bytecode, *subject,
2791cb0ef41Sopenharmony_ci                     regexp->capture_count(), output_registers,
2801cb0ef41Sopenharmony_ci                     output_register_count, subject_index);
2811cb0ef41Sopenharmony_ci}
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ciMaybeHandle<Object> ExperimentalRegExp::OneshotExec(
2841cb0ef41Sopenharmony_ci    Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject,
2851cb0ef41Sopenharmony_ci    int subject_index, Handle<RegExpMatchInfo> last_match_info,
2861cb0ef41Sopenharmony_ci    RegExp::ExecQuirks exec_quirks) {
2871cb0ef41Sopenharmony_ci  DCHECK(FLAG_enable_experimental_regexp_engine_on_excessive_backtracks);
2881cb0ef41Sopenharmony_ci  DCHECK_NE(regexp->type_tag(), JSRegExp::NOT_COMPILED);
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci  int capture_count = regexp->capture_count();
2911cb0ef41Sopenharmony_ci  int output_register_count = JSRegExp::RegistersForCaptureCount(capture_count);
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci  int32_t* output_registers;
2941cb0ef41Sopenharmony_ci  std::unique_ptr<int32_t[]> output_registers_release;
2951cb0ef41Sopenharmony_ci  if (output_register_count <= Isolate::kJSRegexpStaticOffsetsVectorSize) {
2961cb0ef41Sopenharmony_ci    output_registers = isolate->jsregexp_static_offsets_vector();
2971cb0ef41Sopenharmony_ci  } else {
2981cb0ef41Sopenharmony_ci    output_registers = NewArray<int32_t>(output_register_count);
2991cb0ef41Sopenharmony_ci    output_registers_release.reset(output_registers);
3001cb0ef41Sopenharmony_ci  }
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci  int num_matches = OneshotExecRaw(isolate, regexp, subject, output_registers,
3031cb0ef41Sopenharmony_ci                                   output_register_count, subject_index);
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci  if (num_matches > 0) {
3061cb0ef41Sopenharmony_ci    DCHECK_EQ(num_matches, 1);
3071cb0ef41Sopenharmony_ci    if (exec_quirks == RegExp::ExecQuirks::kTreatMatchAtEndAsFailure) {
3081cb0ef41Sopenharmony_ci      if (output_registers[0] >= subject->length()) {
3091cb0ef41Sopenharmony_ci        return isolate->factory()->null_value();
3101cb0ef41Sopenharmony_ci      }
3111cb0ef41Sopenharmony_ci    }
3121cb0ef41Sopenharmony_ci    return RegExp::SetLastMatchInfo(isolate, last_match_info, subject,
3131cb0ef41Sopenharmony_ci                                    capture_count, output_registers);
3141cb0ef41Sopenharmony_ci  } else if (num_matches == 0) {
3151cb0ef41Sopenharmony_ci    return isolate->factory()->null_value();
3161cb0ef41Sopenharmony_ci  } else {
3171cb0ef41Sopenharmony_ci    DCHECK_LT(num_matches, 0);
3181cb0ef41Sopenharmony_ci    DCHECK(isolate->has_pending_exception());
3191cb0ef41Sopenharmony_ci    return MaybeHandle<Object>();
3201cb0ef41Sopenharmony_ci  }
3211cb0ef41Sopenharmony_ci}
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci}  // namespace internal
3241cb0ef41Sopenharmony_ci}  // namespace v8
325