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