diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc index a6e38cd8949..1d3404bf7ad 100644 --- a/runtime/lib/regexp.cc +++ b/runtime/lib/regexp.cc @@ -108,36 +108,33 @@ DEFINE_NATIVE_ENTRY(RegExp_getIsCaseSensitive, 0, 1) { return Bool::Get(!IsIgnoreCase(regexp.flags())).ptr(); } -DEFINE_NATIVE_ENTRY(RegExp_getGroupCount, 0, 1) { - const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0)); - ASSERT(!regexp.IsNull()); - if (regexp.num_bracket_expressions() != -1) { - return Smi::New(regexp.num_bracket_expressions()); - } +static ObjectPtr ThrowUninitialized(const RegExp& regexp) { const String& pattern = String::Handle(regexp.pattern()); const String& errmsg = String::Handle(String::New("Regular expression is not initialized yet.")); const String& message = String::Handle(String::Concat(errmsg, pattern)); const Array& args = Array::Handle(Array::New(1)); args.SetAt(0, message); - Exceptions::ThrowByType(Exceptions::kFormat, args); + Exceptions::ThrowByType(Exceptions::kState, args); return Object::null(); } +DEFINE_NATIVE_ENTRY(RegExp_getGroupCount, 0, 1) { + const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0)); + ASSERT(!regexp.IsNull()); + if (regexp.num_bracket_expressions() != -1) { + return Smi::New(regexp.num_bracket_expressions()); + } + return ThrowUninitialized(regexp); +} + DEFINE_NATIVE_ENTRY(RegExp_getGroupNameMap, 0, 1) { const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0)); ASSERT(!regexp.IsNull()); - if (regexp.num_bracket_expressions() != -1) { + if (regexp.num_bracket_expressions() != -1) { return regexp.capture_name_map(); } - const String& pattern = String::Handle(regexp.pattern()); - const String& errmsg = String::Handle( - String::New("Regular expression is not initialized yet. ")); - const String& message = String::Handle(String::Concat(errmsg, pattern)); - const Array& args = Array::Handle(Array::New(1)); - args.SetAt(0, message); - Exceptions::ThrowByType(Exceptions::kFormat, args); - return Object::null(); + return ThrowUninitialized(regexp); } static ObjectPtr ExecuteMatch(Thread* thread, diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index a699abae15e..f6ef6e24b03 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -27552,10 +27552,6 @@ void RegExp::set_bytecode(bool is_one_byte, } } -void RegExp::set_num_bracket_expressions(intptr_t value) const { - untag()->num_bracket_expressions_ = value; -} - void RegExp::set_capture_name_map(const Array& array) const { untag()->set_capture_name_map(array.ptr()); } diff --git a/runtime/vm/object.h b/runtime/vm/object.h index feb1f299cda..93c52922a97 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -13040,9 +13040,12 @@ class RegExp : public Instance { } StringPtr pattern() const { return untag()->pattern(); } + + template intptr_t num_bracket_expressions() const { - return untag()->num_bracket_expressions_; + return untag()->num_bracket_expressions(); } + ArrayPtr capture_name_map() const { return untag()->capture_name_map(); } @@ -13057,23 +13060,6 @@ class RegExp : public Instance { : untag()->two_byte(); } } - bool has_bytecode(bool is_one_byte, bool sticky) const { - if (sticky) { - if (is_one_byte) { - return Object::null() != - untag()->one_byte_sticky(); - } else { - return Object::null() != - untag()->two_byte_sticky(); - } - } else { - if (is_one_byte) { - return Object::null() != untag()->one_byte(); - } else { - return Object::null() != untag()->two_byte(); - } - } - } static intptr_t function_offset(intptr_t cid, bool sticky) { if (sticky) { @@ -13122,9 +13108,10 @@ class RegExp : public Instance { bool sticky, const TypedData& bytecode) const; - void set_num_bracket_expressions(SmiPtr value) const; - void set_num_bracket_expressions(const Smi& value) const; - void set_num_bracket_expressions(intptr_t value) const; + template + void set_num_bracket_expressions(intptr_t value) const { + return untag()->set_num_bracket_expressions(value); + } void set_capture_name_map(const Array& array) const; void set_num_registers(bool is_one_byte, intptr_t value) const { StoreNonPointer( diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 0660de715bc..65a32d24da6 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -3727,11 +3727,14 @@ class UntaggedRegExp : public UntaggedInstance { CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); } std::atomic num_bracket_expressions_; + + template intptr_t num_bracket_expressions() { - return num_bracket_expressions_.load(std::memory_order_relaxed); + return num_bracket_expressions_.load(order); } + template void set_num_bracket_expressions(intptr_t value) { - num_bracket_expressions_.store(value, std::memory_order_relaxed); + num_bracket_expressions_.store(value, order); } // The same pattern may use different amount of registers if compiled diff --git a/runtime/vm/regexp/regexp-interpreter.cc b/runtime/vm/regexp/regexp-interpreter.cc index 404980fbc52..c5cbc82cc14 100644 --- a/runtime/vm/regexp/regexp-interpreter.cc +++ b/runtime/vm/regexp/regexp-interpreter.cc @@ -1120,9 +1120,9 @@ int IrregexpInterpreter::Match(Thread* thread, bool is_sticky) { // bool is_any_unicode = IsEitherUnicode((regexp_data.flags())); bool is_one_byte = subject_string.IsOneByteString(); - SBXCHECK(regexp_data.has_bytecode(is_one_byte, is_sticky)); const TypedData& code_array = TypedData::Handle(regexp_data.bytecode(is_one_byte, is_sticky)); + SBXCHECK(!code_array.IsNull()); int total_register_count = regexp_data.num_registers(is_one_byte); // MatchInternal only supports returning a single match per call. In global // mode, i.e. when output_registers has space for more than one match, we diff --git a/runtime/vm/regexp/regexp.cc b/runtime/vm/regexp/regexp.cc index 7ee9453cd61..034616d266d 100644 --- a/runtime/vm/regexp/regexp.cc +++ b/runtime/vm/regexp/regexp.cc @@ -180,7 +180,7 @@ bool RegExpImpl::EnsureCompiledIrregexp(Thread* thread, const String& sample_subject, bool is_one_byte, bool sticky) { - if (re_data.has_bytecode(is_one_byte, sticky)) return true; + if (re_data.bytecode(is_one_byte, sticky) != TypedData::null()) return true; return CompileIrregexpFromSource(thread, re_data, sample_subject, is_one_byte, sticky, RegExpCompilationTarget::kBytecode); @@ -277,22 +277,24 @@ bool RegExpImpl::CompileIrregexpFromSource( return false; } - if (compile_data.compilation_target == RegExpCompilationTarget::kNative) { - UNREACHABLE(); - } else { - DCHECK_EQ(compile_data.compilation_target, - RegExpCompilationTarget::kBytecode); - // Store code generated by compiler in bytecode and trampoline to - // interpreter in code. - re_data.set_bytecode(is_one_byte, sticky, - TypedData::Cast(*compile_data.code)); - } + // Set num_bracket_expression after setting capture_name_map. + // RegExp_getGroupNameMap will read num_bracket_expression first and assume + // capture_name_map is available if the count is not -1. const Array& capture_name_map = Array::Handle(zone, RegExpStatics::CreateCaptureNameMap( thread->isolate(), compile_data.named_captures)); re_data.set_capture_name_map(capture_name_map); + re_data.set_num_bracket_expressions( + compile_data.capture_count); + + // Set bytecode after setting num_registers. RegExpStatics::Interpret will + // read bytecode first and assume num_register is available if bytecode is not + // null. re_data.set_num_registers(is_one_byte, compile_data.register_count); - re_data.set_num_bracket_expressions(compile_data.capture_count); + DCHECK_EQ(compile_data.compilation_target, + RegExpCompilationTarget::kBytecode); + re_data.set_bytecode(is_one_byte, sticky, + TypedData::Cast(*compile_data.code)); return true; } @@ -493,7 +495,7 @@ ObjectPtr RegExpStatics::Interpret(Thread* thread, int start_index, bool sticky) { bool is_one_byte = subject.IsOneByteString(); - if (!regexp.has_bytecode(is_one_byte, sticky)) { + if (regexp.bytecode(is_one_byte, sticky) == TypedData::null()) { if (!RegExpImpl::CompileIrregexpFromSource( thread, regexp, subject, is_one_byte, sticky, RegExpCompilationTarget::kBytecode)) { diff --git a/runtime/vm/regexp/special-case.cc b/runtime/vm/regexp/special-case.cc index 4f4d294c66e..773a3c81b29 100644 --- a/runtime/vm/regexp/special-case.cc +++ b/runtime/vm/regexp/special-case.cc @@ -10,11 +10,12 @@ // the algorithm defined in ECMAScript 2020 21.2.2.8.2 (Runtime // Semantics: Canonicalize) step 3. -#if 1 /*V8_INTL_SUPPORT*/ - #include "vm/regexp/special-case.h" +#include + #include "unicode/uniset.h" + namespace dart { icu::UnicodeSet BuildIgnoreSet() { @@ -49,9 +50,8 @@ struct IgnoreSetData { //static const icu::UnicodeSet& RegExpCaseFolding::IgnoreSet() { static IgnoreSetData* set = nullptr; - if (set == nullptr) { - set = new IgnoreSetData(); - } + static std::once_flag init_once = {}; + std::call_once(init_once, [] { set = new IgnoreSetData(); }); return set->set; } @@ -80,11 +80,9 @@ struct SpecialAddSetData { //static const icu::UnicodeSet& RegExpCaseFolding::SpecialAddSet() { static SpecialAddSetData* set = nullptr; - if (set == nullptr) { - set = new SpecialAddSetData(); - } + static std::once_flag init_once = {}; + std::call_once(init_once, [] { set = new SpecialAddSetData(); }); return set->set; } } // namespace dart -#endif // V8_INTL_SUPPORT