[vm] Fix race compiling regexp.
TEST=iso-stress Change-Id: I013d7d91d37b62ed60d7f067a62c6f419c0d0a7c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/483362 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
committed by
Commit Queue
parent
96611671aa
commit
d5e2f31993
+13
-16
@@ -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<std::memory_order_acquire>() != -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,
|
||||
|
||||
@@ -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<std::memory_order_release>(array.ptr());
|
||||
}
|
||||
|
||||
+8
-21
@@ -13040,9 +13040,12 @@ class RegExp : public Instance {
|
||||
}
|
||||
|
||||
StringPtr pattern() const { return untag()->pattern(); }
|
||||
|
||||
template <std::memory_order order = std::memory_order_relaxed>
|
||||
intptr_t num_bracket_expressions() const {
|
||||
return untag()->num_bracket_expressions_;
|
||||
return untag()->num_bracket_expressions<order>();
|
||||
}
|
||||
|
||||
ArrayPtr capture_name_map() const {
|
||||
return untag()->capture_name_map<std::memory_order_acquire>();
|
||||
}
|
||||
@@ -13057,23 +13060,6 @@ class RegExp : public Instance {
|
||||
: untag()->two_byte<std::memory_order_acquire>();
|
||||
}
|
||||
}
|
||||
bool has_bytecode(bool is_one_byte, bool sticky) const {
|
||||
if (sticky) {
|
||||
if (is_one_byte) {
|
||||
return Object::null() !=
|
||||
untag()->one_byte_sticky<std::memory_order_relaxed>();
|
||||
} else {
|
||||
return Object::null() !=
|
||||
untag()->two_byte_sticky<std::memory_order_relaxed>();
|
||||
}
|
||||
} else {
|
||||
if (is_one_byte) {
|
||||
return Object::null() != untag()->one_byte<std::memory_order_relaxed>();
|
||||
} else {
|
||||
return Object::null() != untag()->two_byte<std::memory_order_relaxed>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 <std::memory_order order = std::memory_order_relaxed>
|
||||
void set_num_bracket_expressions(intptr_t value) const {
|
||||
return untag()->set_num_bracket_expressions<order>(value);
|
||||
}
|
||||
void set_capture_name_map(const Array& array) const;
|
||||
void set_num_registers(bool is_one_byte, intptr_t value) const {
|
||||
StoreNonPointer<intptr_t, intptr_t, std::memory_order_relaxed>(
|
||||
|
||||
@@ -3727,11 +3727,14 @@ class UntaggedRegExp : public UntaggedInstance {
|
||||
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
|
||||
|
||||
std::atomic<intptr_t> num_bracket_expressions_;
|
||||
|
||||
template <std::memory_order order = std::memory_order_relaxed>
|
||||
intptr_t num_bracket_expressions() {
|
||||
return num_bracket_expressions_.load(std::memory_order_relaxed);
|
||||
return num_bracket_expressions_.load(order);
|
||||
}
|
||||
template <std::memory_order order = std::memory_order_relaxed>
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
+15
-13
@@ -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<std::memory_order_release>(
|
||||
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)) {
|
||||
|
||||
@@ -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 <mutex>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user