Index: runtime/vm/regexp_assembler.cc |
diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc |
index ace86912cfc151909945fd01429d14c0bacc68d4..c1d5d510c17feadd078f3c8764db29dc8292abab 100644 |
--- a/runtime/vm/regexp_assembler.cc |
+++ b/runtime/vm/regexp_assembler.cc |
@@ -62,7 +62,7 @@ void PrintUtf16(uint16_t c) { |
* [start_inclusive, end_exclusive] for capture group i are stored at positions |
* matches_param_[i * 2] and matches_param_[i * 2 + 1], respectively. Match |
* indices of -1 denote non-matched groups. Note that we store these indices |
- * as a negative offset from the end of the string in position_registers_ |
+ * as a negative offset from the end of the string in registers_array_ |
* during processing, and convert them to standard indexes when copying them |
* to matches_param_ on successful match. |
*/ |
@@ -95,9 +95,12 @@ IRRegExpMacroAssembler::IRRegExpMacroAssembler( |
string_param_(NULL), |
string_param_length_(NULL), |
start_index_param_(NULL), |
- position_registers_count_((capture_count + 1) * 2), |
+ registers_count_(0), |
+ saved_registers_count_((capture_count + 1) * 2), |
stack_array_(GrowableObjectArray::ZoneHandle( |
- isolate, GrowableObjectArray::New(16, Heap::kOld))) { |
+ isolate, GrowableObjectArray::New(16, Heap::kOld))), |
+ // The registers array is allocated at a fixed size after assembly. |
+ registers_array_(TypedData::ZoneHandle(isolate, TypedData::null())) { |
switch (specialization_cid) { |
case kOneByteStringCid: |
case kExternalOneByteStringCid: mode_ = ASCII; break; |
@@ -149,6 +152,7 @@ void IRRegExpMacroAssembler::InitializeLocals() { |
// Create local variables and parameters. |
stack_ = Local(Symbols::stack()); |
+ registers_ = Local(Symbols::position_registers()); |
current_character_ = Local(Symbols::current_character()); |
current_position_ = Local(Symbols::current_position()); |
string_param_length_ = Local(Symbols::string_param_length()); |
@@ -163,12 +167,6 @@ void IRRegExpMacroAssembler::InitializeLocals() { |
string_param_ = Parameter(Symbols::string_param(), 0); |
start_index_param_ = Parameter(Symbols::start_index_param(), 1); |
- |
- // Reserve space for all captured group positions. Note that more might |
- // be created on the fly for internal use. |
- for (intptr_t i = 0; i < position_registers_count_; i++) { |
- position_register(i); |
- } |
} |
@@ -176,11 +174,6 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { |
set_current_instruction(entry_block_->normal_entry()); |
TAG(); |
- // Generate a local list variable which we will use as a backtracking stack. |
- |
- StoreLocal(stack_, Bind(new(I) ConstantInstr(stack_array_))); |
- Do(InstanceCall(InstanceCallDescriptor(Symbols::clear()), PushLocal(stack_))); |
- |
// Store string.length. |
PushArgumentInstr* string_push = PushLocal(string_param_); |
@@ -191,9 +184,6 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { |
String::ZoneHandle(Field::GetterSymbol(Symbols::Length()))), |
string_push))); |
- // Initialize all capture registers. |
- ClearRegisters(0, position_registers_count_ - 1); |
- |
// Store (start_index - string.length) as the current position (since it's a |
// negative offset from the end of the string). |
PushArgumentInstr* start_index_push = PushLocal(start_index_param_); |
@@ -201,6 +191,16 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { |
StoreLocal(current_position_, Bind(Sub(start_index_push, length_push))); |
+ // Generate a local list variable to represent "registers" and |
+ // initialize capture registers (others remain garbage). |
+ StoreLocal(registers_, Bind(new(I) ConstantInstr(registers_array_))); |
+ ClearRegisters(0, saved_registers_count_ - 1); |
+ |
+ // Generate a local list variable to represent the backtracking stack. |
+ StoreLocal(stack_, Bind(new(I) ConstantInstr(stack_array_))); |
+ PushArgumentInstr* stack_push = PushLocal(stack_); |
+ Do(InstanceCall(InstanceCallDescriptor(Symbols::clear()), stack_push)); |
+ |
// Jump to the start block. |
current_instruction_->Goto(start_block_); |
} |
@@ -240,30 +240,20 @@ void IRRegExpMacroAssembler::GenerateSuccessBlock() { |
set_current_instruction(success_block_); |
TAG(); |
- Definition* type_args_null_def = new(I) ConstantInstr( |
- TypeArguments::ZoneHandle(I, TypeArguments::null())); |
- PushArgumentInstr* type_arg_push = PushArgument(Bind(type_args_null_def)); |
- PushArgumentInstr* length_push = |
- PushArgument(Bind(Uint64Constant(position_registers_count_))); |
- |
- const Library& lib = Library::Handle(Library::CoreLibrary()); |
- const Class& list_class = Class::Handle( |
- lib.LookupCoreClass(Symbols::List())); |
- const Function& list_ctor = |
- Function::ZoneHandle(I, list_class.LookupFactory(Symbols::ListFactory())); |
- |
- // TODO(zerny): Use CreateArrayInstr and StoreIndexed instead. |
- StoreLocal(result_, Bind(StaticCall(list_ctor, type_arg_push, length_push))); |
+ Value* type = Bind(new(I) ConstantInstr( |
+ TypeArguments::ZoneHandle(I, TypeArguments::null()))); |
+ Value* length = Bind(Uint64Constant(saved_registers_count_)); |
+ Value* array = Bind(new(I) CreateArrayInstr(kNoSourcePos, type, length)); |
+ StoreLocal(result_, array); |
// Store captured offsets in the `matches` parameter. |
- // TODO(zerny): Eliminate position_register locals and access `matches` |
- // directly. |
- for (intptr_t i = 0; i < position_registers_count_; i++) { |
+ for (intptr_t i = 0; i < saved_registers_count_; i++) { |
PushArgumentInstr* matches_push = PushLocal(result_); |
PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i))); |
// Convert negative offsets from the end of the string to string indices. |
- PushArgumentInstr* offset_push = PushLocal(position_register(i)); |
+ // TODO(zerny): use positive offsets from the get-go. |
+ PushArgumentInstr* offset_push = PushArgument(LoadRegister(i)); |
PushArgumentInstr* len_push = PushLocal(string_param_length_); |
PushArgumentInstr* value_push = |
PushArgument(Bind(Add(offset_push, len_push))); |
@@ -291,6 +281,13 @@ void IRRegExpMacroAssembler::GenerateExitBlock() { |
} |
+void IRRegExpMacroAssembler::FinalizeRegistersArray() { |
+ ASSERT(registers_count_ >= saved_registers_count_); |
+ registers_array_ = |
+ TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld); |
+} |
+ |
+ |
#if defined(TARGET_ARCH_ARM64) || \ |
defined(TARGET_ARCH_ARM) || \ |
defined(TARGET_ARCH_MIPS) |
@@ -436,7 +433,7 @@ ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const { |
ComparisonInstr* IRRegExpMacroAssembler::Comparison( |
- ComparisonKind kind, Definition* lhs, Definition* rhs) { |
+ ComparisonKind kind, PushArgumentInstr* lhs, PushArgumentInstr* rhs) { |
Token::Kind strict_comparison = Token::kEQ_STRICT; |
Token::Kind intermediate_operator = Token::kILLEGAL; |
switch (kind) { |
@@ -465,20 +462,24 @@ ComparisonInstr* IRRegExpMacroAssembler::Comparison( |
ASSERT(intermediate_operator != Token::kILLEGAL); |
- PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); |
- PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); |
- |
Value* lhs_value = |
Bind(InstanceCall( |
InstanceCallDescriptor::FromToken(intermediate_operator), |
- lhs_push, |
- rhs_push)); |
+ lhs, |
+ rhs)); |
Value* rhs_value = Bind(BoolConstant(true)); |
return new(I) StrictCompareInstr( |
kNoSourcePos, strict_comparison, lhs_value, rhs_value, true); |
} |
+ComparisonInstr* IRRegExpMacroAssembler::Comparison( |
+ ComparisonKind kind, Definition* lhs, Definition* rhs) { |
+ PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); |
+ PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); |
+ return Comparison(kind, lhs_push, rhs_push); |
+} |
+ |
StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
const Function& function) const { |
@@ -735,12 +736,15 @@ void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) { |
void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) { |
TAG(); |
ASSERT(reg >= 0); |
- ASSERT(reg < position_registers_.length()); |
+ ASSERT(reg < registers_count_); |
if (by != 0) { |
- PushArgumentInstr* reg_push = PushLocal(position_register(reg)); |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(reg); |
+ PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); |
- StoreLocal(position_register(reg), Bind(Add(reg_push, by_push))); |
+ PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push))); |
+ StoreRegister(registers_push, index_push, value_push); |
} |
} |
@@ -777,13 +781,37 @@ intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() { |
} |
-LocalVariable* IRRegExpMacroAssembler::position_register(intptr_t index) { |
- // Create position registers as needed. |
- for (intptr_t i = position_registers_.length(); i < index + 1; i++) { |
- position_registers_.Add(Local(Symbols::position_registers())); |
- } |
+Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) { |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(index); |
+ return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
+ registers_push, |
+ index_push)); |
+} |
+ |
+void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) { |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(index); |
+ PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value))); |
+ StoreRegister(registers_push, index_push, value_push); |
+} |
+ |
+ |
+void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers, |
+ PushArgumentInstr* index, |
+ PushArgumentInstr* value) { |
+ TAG(); |
+ Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
+ registers, |
+ index, |
+ value)); |
+} |
- return position_registers_[index]; |
+PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) { |
+ if (registers_count_ <= index) { |
+ registers_count_ = index + 1; |
+ } |
+ return PushArgument(Bind(Uint64Constant(index))); |
} |
@@ -890,12 +918,12 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( |
intptr_t start_reg, |
BlockLabel* on_no_match) { |
TAG(); |
- ASSERT(start_reg + 1 <= position_registers_.length()); |
+ ASSERT(start_reg + 1 <= registers_count_); |
BlockLabel fallthrough; |
- PushArgumentInstr* end_push = PushLocal(position_register(start_reg + 1)); |
- PushArgumentInstr* start_push = PushLocal(position_register(start_reg)); |
+ PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); |
+ PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); |
StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); |
// The length of a capture should not be negative. This can only happen |
@@ -931,7 +959,7 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( |
len_push = PushLocal(string_param_length_); |
StoreLocal(match_start_index_, Bind(Add(pos_push, len_push))); |
- pos_push = PushLocal(position_register(start_reg)); |
+ pos_push = PushArgument(LoadRegister(start_reg)); |
len_push = PushLocal(string_param_length_); |
StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push))); |
@@ -1057,14 +1085,14 @@ void IRRegExpMacroAssembler::CheckNotBackReference( |
intptr_t start_reg, |
BlockLabel* on_no_match) { |
TAG(); |
- ASSERT(start_reg + 1 <= position_registers_.length()); |
+ ASSERT(start_reg + 1 <= registers_count_); |
BlockLabel fallthrough; |
BlockLabel success; |
// Find length of back-referenced capture. |
- PushArgumentInstr* end_push = PushLocal(position_register(start_reg + 1)); |
- PushArgumentInstr* start_push = PushLocal(position_register(start_reg)); |
+ PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); |
+ PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); |
StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); |
// Fail on partial or illegal capture (start of capture after end of capture). |
@@ -1095,7 +1123,7 @@ void IRRegExpMacroAssembler::CheckNotBackReference( |
len_push = PushLocal(string_param_length_); |
StoreLocal(match_start_index_, Bind(Add(pos_push, len_push))); |
- pos_push = PushLocal(position_register(start_reg)); |
+ pos_push = PushArgument(LoadRegister(start_reg)); |
len_push = PushLocal(string_param_length_); |
StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push))); |
@@ -1448,10 +1476,9 @@ void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg, |
intptr_t comparand, |
BlockLabel* if_ge) { |
TAG(); |
- BranchOrBacktrack(Comparison(kGTE, |
- LoadLocal(position_register(reg)), |
- Int64Constant(comparand)), |
- if_ge); |
+ PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
+ PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); |
+ BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge); |
} |
@@ -1459,20 +1486,18 @@ void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg, |
intptr_t comparand, |
BlockLabel* if_lt) { |
TAG(); |
- BranchOrBacktrack(Comparison(kLT, |
- LoadLocal(position_register(reg)), |
- Int64Constant(comparand)), |
- if_lt); |
+ PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
+ PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); |
+ BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt); |
} |
void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg, |
BlockLabel* if_eq) { |
TAG(); |
- BranchOrBacktrack(Comparison(kEQ, |
- LoadLocal(position_register(reg)), |
- LoadLocal(current_position_)), |
- if_eq); |
+ PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
+ PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_))); |
+ BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq); |
} |
@@ -1502,10 +1527,13 @@ void IRRegExpMacroAssembler::PopCurrentPosition() { |
} |
-void IRRegExpMacroAssembler::PopRegister(intptr_t register_index) { |
+void IRRegExpMacroAssembler::PopRegister(intptr_t reg) { |
TAG(); |
- ASSERT(register_index < position_registers_.length()); |
- StoreLocal(position_register(register_index), PopStack()); |
+ ASSERT(reg < registers_count_); |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(reg); |
+ PushArgumentInstr* pop_push = PushArgument(PopStack()); |
+ StoreRegister(registers_push, index_push, pop_push); |
} |
@@ -1548,24 +1576,28 @@ void IRRegExpMacroAssembler::PushCurrentPosition() { |
} |
-void IRRegExpMacroAssembler::PushRegister(intptr_t register_index) { |
+void IRRegExpMacroAssembler::PushRegister(intptr_t reg) { |
TAG(); |
- PushStack(LoadLocal(position_register(register_index))); |
+ PushArgumentInstr* stack_push = PushLocal(stack_); |
+ PushArgumentInstr* value_push = PushArgument(LoadRegister(reg)); |
+ Do(InstanceCall(InstanceCallDescriptor(Symbols::add()), |
+ stack_push, |
+ value_push)); |
} |
void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) { |
TAG(); |
- StoreLocal(current_position_, Bind(LoadLocal(position_register(reg)))); |
+ StoreLocal(current_position_, LoadRegister(reg)); |
} |
// Resets the size of the stack to the value stored in reg. |
void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) { |
TAG(); |
- ASSERT(reg < position_registers_.length()); |
+ ASSERT(reg < registers_count_); |
PushArgumentInstr* stack_push = PushLocal(stack_); |
- PushArgumentInstr* length_push = PushLocal(position_register(reg)); |
+ PushArgumentInstr* length_push = PushArgument(LoadRegister(reg)); |
Do(InstanceCall( |
InstanceCallDescriptor( |
@@ -1596,11 +1628,11 @@ void IRRegExpMacroAssembler::SetCurrentPositionFromEnd(intptr_t by) { |
} |
-void IRRegExpMacroAssembler::SetRegister(intptr_t register_index, intptr_t to) { |
+void IRRegExpMacroAssembler::SetRegister(intptr_t reg, intptr_t to) { |
TAG(); |
// Reserved for positions! |
- ASSERT(register_index >= position_registers_count_); |
- StoreLocal(position_register(register_index), Bind(Int64Constant(to))); |
+ ASSERT(reg >= saved_registers_count_); |
+ StoreRegister(reg, to); |
} |
@@ -1615,13 +1647,14 @@ void IRRegExpMacroAssembler::WriteCurrentPositionToRegister( |
intptr_t reg, intptr_t cp_offset) { |
TAG(); |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(reg); |
PushArgumentInstr* pos_push = PushLocal(current_position_); |
- PushArgumentInstr* off_push = |
- PushArgument(Bind(Int64Constant(cp_offset))); |
- |
+ PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset))); |
+ PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push))); |
// Push the negative offset; these are converted to positive string positions |
// within the success block. |
- StoreLocal(position_register(reg), Bind(Add(pos_push, off_push))); |
+ StoreRegister(registers_push, index_push, neg_off_push); |
} |
@@ -1630,17 +1663,19 @@ void IRRegExpMacroAssembler::ClearRegisters( |
TAG(); |
ASSERT(reg_from <= reg_to); |
- ASSERT(reg_to < position_registers_.length()); |
// In order to clear registers to a final result value of -1, set them to |
// (-1 - string length), the offset of -1 from the end of the string. |
for (intptr_t reg = reg_from; reg <= reg_to; reg++) { |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(reg); |
PushArgumentInstr* minus_one_push = |
PushArgument(Bind(Int64Constant(-1))); |
PushArgumentInstr* length_push = PushLocal(string_param_length_); |
- |
- StoreLocal(position_register(reg), Bind(Sub(minus_one_push, length_push))); |
+ PushArgumentInstr* value_push = |
+ PushArgument(Bind(Sub(minus_one_push, length_push))); |
+ StoreRegister(registers_push, index_push, value_push); |
} |
} |
@@ -1648,14 +1683,14 @@ void IRRegExpMacroAssembler::ClearRegisters( |
void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) { |
TAG(); |
+ PushArgumentInstr* registers_push = PushLocal(registers_); |
+ PushArgumentInstr* index_push = PushRegisterIndex(reg); |
PushArgumentInstr* stack_push = PushLocal(stack_); |
- Value* length_value = |
- Bind(InstanceCall(InstanceCallDescriptor( |
- String::ZoneHandle( |
- I, Field::GetterSymbol(Symbols::Length()))), |
- stack_push)); |
- |
- StoreLocal(position_register(reg), length_value); |
+ PushArgumentInstr* length_push = |
+ PushArgument(Bind(InstanceCall(InstanceCallDescriptor( |
+ String::ZoneHandle(I, Field::GetterSymbol(Symbols::Length()))), |
+ stack_push))); |
+ StoreRegister(registers_push, index_push, length_push); |
} |