12#include "unicode/uniset.h"
22#if !defined(DART_PRECOMPILED_RUNTIME)
37 const int32_t* ranges,
38 intptr_t ranges_length,
40 ASSERT((ranges_length & 1) == 1);
45 for (intptr_t
i = 0;
i < ranges_length;
46 inside = !inside, last = ranges[
i],
i++) {
49 if (ranges[
i] <= new_range.
from())
continue;
52 if (last <= new_range.
from() && new_range.
to() < ranges[
i]) {
221 for (intptr_t
i = 0;
i <
elements()->length();
i++)
249 frequencies_[
i] = CharacterFrequency(
i);
255 frequencies_[index].Increment();
263 if (total_samples_ < 1)
return 1;
264 intptr_t freq_in_per128 =
265 (frequencies_[in_character].counter() * 128) / total_samples_;
266 return freq_in_per128;
270 class CharacterFrequency {
272 CharacterFrequency() : counter_(0), character_(-1) {}
273 explicit CharacterFrequency(intptr_t
character)
276 void Increment() { counter_++; }
277 intptr_t counter() {
return counter_; }
278 intptr_t
character() {
return character_; }
289 intptr_t total_samples_;
301 if (unicode_lookaround_stack_register_ ==
kNoRegister) {
304 return unicode_lookaround_stack_register_;
308 if (unicode_lookaround_position_register_ ==
kNoRegister) {
311 return unicode_lookaround_position_register_;
314#if !defined(DART_PRECOMPILED_RUNTIME)
317 intptr_t capture_count,
324 intptr_t capture_count,
343 inline bool one_byte()
const {
return is_one_byte_; }
350 current_expansion_factor_ =
value;
359 intptr_t next_register_;
360 intptr_t unicode_lookaround_stack_register_;
361 intptr_t unicode_lookaround_position_register_;
363 intptr_t recursion_depth_;
366 bool reg_exp_too_big_;
368 intptr_t current_expansion_factor_;
376 compiler->IncrementRecursionDepth();
391 : next_register_(2 * (capture_count + 1)),
393 unicode_lookaround_position_register_(
kNoRegister),
396 is_one_byte_(is_one_byte),
397 reg_exp_too_big_(
false),
398 read_backward_(
false),
399 current_expansion_factor_(1),
400 zone_(
Thread::Current()->zone()) {
404#if !defined(DART_PRECOMPILED_RUNTIME)
408 intptr_t capture_count,
414 work_list_ = &work_list;
418 start->Emit(
this, &new_trace);
420 macro_assembler_->
Fail();
422 work_list.
RemoveLast()->Emit(
this, &new_trace);
439 intptr_t capture_count,
445 work_list_ = &work_list;
449 start->Emit(
this, &new_trace);
451 macro_assembler_->
Fail();
453 work_list.
RemoveLast()->Emit(
this, &new_trace);
466 return reg() == that;
473 if (
action->Mentions(reg))
return true;
482 if (
action->Mentions(reg)) {
497intptr_t Trace::FindAffectedRegisters(
OutSet* affected_registers,
Zone* zone) {
499 for (DeferredAction*
action = actions_;
action !=
nullptr;
502 Interval range =
static_cast<DeferredClearCaptures*
>(
action)->range();
503 for (intptr_t
i = range.
from();
i <= range.
to();
i++)
504 affected_registers->Set(
i, zone);
505 if (range.
to() > max_register) max_register = range.
to();
507 affected_registers->Set(
action->reg(), zone);
508 if (
action->reg() > max_register) max_register =
action->reg();
514void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler,
515 intptr_t max_register,
516 const OutSet& registers_to_pop,
517 const OutSet& registers_to_clear) {
518 for (intptr_t reg = max_register; reg >= 0; reg--) {
519 if (registers_to_pop.Get(reg)) {
520 assembler->PopRegister(reg);
521 }
else if (registers_to_clear.Get(reg)) {
522 intptr_t clear_to = reg;
523 while (reg > 0 && registers_to_clear.Get(reg - 1)) {
526 assembler->ClearRegisters(reg, clear_to);
531void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
532 intptr_t max_register,
533 const OutSet& affected_registers,
534 OutSet* registers_to_pop,
535 OutSet* registers_to_clear,
537 for (intptr_t reg = 0; reg <= max_register; reg++) {
538 if (!affected_registers.Get(reg)) {
545 enum DeferredActionUndoType { ACTION_IGNORE, ACTION_RESTORE, ACTION_CLEAR };
546 DeferredActionUndoType undo_action = ACTION_IGNORE;
549 bool absolute =
false;
552 intptr_t store_position = kNoStore;
555 for (DeferredAction*
action = actions_;
action !=
nullptr;
557 if (
action->Mentions(reg)) {
558 switch (
action->action_type()) {
560 Trace::DeferredSetRegister* psr =
561 static_cast<Trace::DeferredSetRegister*
>(
action);
563 value += psr->value();
571 undo_action = ACTION_RESTORE;
572 ASSERT(store_position == kNoStore);
580 ASSERT(store_position == kNoStore);
582 undo_action = ACTION_RESTORE;
585 Trace::DeferredCapture* pc =
586 static_cast<Trace::DeferredCapture*
>(
action);
587 if (!clear && store_position == kNoStore) {
588 store_position = pc->cp_offset();
599 undo_action = ACTION_IGNORE;
601 undo_action = pc->is_capture() ? ACTION_CLEAR : ACTION_RESTORE;
611 if (store_position == kNoStore) {
614 undo_action = ACTION_RESTORE;
626 if (undo_action == ACTION_RESTORE) {
627 assembler->PushRegister(reg);
628 registers_to_pop->Set(reg, zone);
629 }
else if (undo_action == ACTION_CLEAR) {
630 registers_to_clear->Set(reg, zone);
634 if (store_position != kNoStore) {
635 assembler->WriteCurrentPositionToRegister(reg, store_position);
637 assembler->ClearRegisters(reg, reg);
638 }
else if (absolute) {
639 assembler->SetRegister(reg,
value);
640 }
else if (
value != 0) {
641 assembler->AdvanceRegister(reg,
value);
654 if (actions_ ==
nullptr &&
backtrack() ==
nullptr) {
666 OutSet affected_registers;
675 intptr_t max_register = FindAffectedRegisters(&affected_registers, zone);
677 OutSet registers_to_clear;
678 PerformDeferredActions(assembler, max_register, affected_registers,
679 ®isters_to_pop, ®isters_to_clear, zone);
680 if (cp_offset_ != 0) {
692 RestoreAffectedRegisters(assembler, max_register, registers_to_pop,
707 if (!label()->is_bound()) {
717 if (clear_capture_count_ > 0) {
720 int clear_capture_end = clear_capture_start_ + clear_capture_count_ - 1;
721 assembler->
ClearRegisters(clear_capture_start_, clear_capture_end);
734 if (!label()->is_bound()) {
744 case NEGATIVE_SUBMATCH_SUCCESS:
761 result->data_.u_store_register.reg = reg;
762 result->data_.u_store_register.value = val;
769 new (on_success->
zone())
ActionNode(INCREMENT_REGISTER, on_success);
770 result->data_.u_increment_register.reg = reg;
779 result->data_.u_position_register.reg = reg;
780 result->data_.u_position_register.is_capture = is_capture;
787 result->data_.u_clear_captures.range_from = range.
from();
788 result->data_.u_clear_captures.range_to = range.
to();
793 intptr_t position_reg,
797 result->data_.u_submatch.stack_pointer_register = stack_reg;
798 result->data_.u_submatch.current_position_register = position_reg;
803 intptr_t position_reg,
804 intptr_t clear_register_count,
805 intptr_t clear_register_from,
808 ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success);
809 result->data_.u_submatch.stack_pointer_register = stack_reg;
810 result->data_.u_submatch.current_position_register = position_reg;
811 result->data_.u_submatch.clear_register_count = clear_register_count;
812 result->data_.u_submatch.clear_register_from = clear_register_from;
817 intptr_t repetition_register,
818 intptr_t repetition_limit,
821 new (on_success->
zone())
ActionNode(EMPTY_MATCH_CHECK, on_success);
822 result->data_.u_empty_match_check.start_register = start_register;
823 result->data_.u_empty_match_check.repetition_register = repetition_register;
824 result->data_.u_empty_match_check.repetition_limit = repetition_limit;
828#define DEFINE_ACCEPT(Type) \
829 void Type##Node::Accept(NodeVisitor* visitor) { \
830 visitor->Visit##Type(this); \
845 switch (guard->
op()) {
862 bool one_byte_subject,
891 bool bound_checked =
false;
894 bound_checked =
true;
897 return bound_checked;
910 bool one_byte =
compiler->one_byte();
919 bool checked =
false;
946 uint16_t exor = c1 ^ c2;
948 if (((exor - 1) & exor) == 0) {
952 uint16_t mask = char_mask ^ exor;
957 uint16_t diff = c2 - c1;
958 if (((diff - 1) & diff) == 0 && c1 >= diff) {
963 uint16_t mask = char_mask ^ diff;
989 bool one_byte =
compiler->one_byte();
992 if (
length <= 1)
return false;
1003 chars[1], on_failure)) {
1032 if (below != fall_through) {
1034 if (above_or_equal != fall_through) masm->
GoTo(above_or_equal);
1046 if (in_range == fall_through) {
1047 if (first == last) {
1053 if (first == last) {
1058 if (out_of_range != fall_through) masm->
GoTo(out_of_range);
1066 intptr_t start_index,
1075 intptr_t
base = (min_char & ~kMask);
1078 for (intptr_t
i = start_index;
i <= end_index;
i++) {
1081 ASSERT(start_index == 0 || (ranges->
At(start_index - 1) & ~kMask) <=
base);
1087 if (even_label == fall_through) {
1088 on_bit_set = odd_label;
1089 on_bit_clear = even_label;
1092 on_bit_set = even_label;
1093 on_bit_clear = odd_label;
1096 for (intptr_t
i = 0;
i < (ranges->
At(start_index) & kMask) &&
i < kSize;
1102 for (intptr_t
i = start_index;
i < end_index;
i++) {
1103 for (j = (ranges->
At(
i) & kMask); j < (ranges->
At(
i + 1) & kMask); j++) {
1108 for (intptr_t
i = j;
i < kSize;
i++) {
1114 for (intptr_t
i = 0;
i < kSize;
i++) {
1115 ba.SetUint8(
i, templ[
i]);
1118 if (on_bit_clear != fall_through) masm->
GoTo(on_bit_clear);
1123 intptr_t start_index,
1128 bool odd = (((cut_index - start_index) & 1) == 1);
1129 BlockLabel* in_range_label = odd ? odd_label : even_label;
1132 ranges->
At(cut_index + 1) - 1, &dummy, in_range_label,
1138 for (intptr_t j = cut_index; j > start_index; j--) {
1139 (*ranges)[j] = ranges->
At(j - 1);
1141 for (intptr_t j = cut_index + 1; j < end_index; j++) {
1142 (*ranges)[j] = ranges->
At(j + 1);
1149 intptr_t start_index,
1151 intptr_t* new_start_index,
1152 intptr_t* new_end_index,
1157 uint16_t first = ranges->
At(start_index);
1158 uint16_t last = ranges->
At(end_index) - 1;
1160 *new_start_index = start_index;
1161 *border = (ranges->
At(start_index) & ~kMask) + kSize;
1162 while (*new_start_index < end_index) {
1163 if (ranges->
At(*new_start_index) > *border)
break;
1164 (*new_start_index)++;
1177 intptr_t binary_chop_index = (end_index + start_index) / 2;
1183 end_index - start_index > (*new_start_index - start_index) * 2 &&
1184 last - first > kSize * 2 && binary_chop_index > *new_start_index &&
1185 ranges->
At(binary_chop_index) >= first + 2 * kSize) {
1186 intptr_t scan_forward_for_section_border = binary_chop_index;
1187 intptr_t new_border = (ranges->
At(binary_chop_index) | kMask) + 1;
1189 while (scan_forward_for_section_border < end_index) {
1190 if (ranges->
At(scan_forward_for_section_border) > new_border) {
1191 *new_start_index = scan_forward_for_section_border;
1192 *border = new_border;
1195 scan_forward_for_section_border++;
1199 ASSERT(*new_start_index > start_index);
1200 *new_end_index = *new_start_index - 1;
1201 if (ranges->
At(*new_end_index) == *border) {
1204 if (*border >= ranges->
At(end_index)) {
1205 *border = ranges->
At(end_index);
1206 *new_start_index = end_index;
1207 *new_end_index = end_index - 1;
1219 intptr_t start_index,
1226 uint16_t first = ranges->
At(start_index);
1227 uint16_t last = ranges->
At(end_index) - 1;
1229 ASSERT(min_char < first);
1233 if (start_index == end_index) {
1240 if (start_index + 1 == end_index) {
1248 if (end_index - start_index <= 6) {
1251 static intptr_t kNoCutIndex = -1;
1252 intptr_t cut = kNoCutIndex;
1253 for (intptr_t
i = start_index;
i < end_index;
i++) {
1254 if (ranges->
At(
i) == ranges->
At(
i + 1) - 1) {
1259 if (cut == kNoCutIndex) cut = start_index;
1260 CutOutRange(masm, ranges, start_index, end_index, cut, even_label,
1262 ASSERT(end_index - start_index >= 2);
1264 max_char, fall_through, even_label, odd_label);
1272 if ((max_char >>
kBits) == (min_char >>
kBits)) {
1274 fall_through, even_label, odd_label);
1278 if ((min_char >>
kBits) != (first >>
kBits)) {
1280 GenerateBranches(masm, ranges, start_index + 1, end_index, first, max_char,
1281 fall_through, odd_label, even_label);
1285 intptr_t new_start_index = 0;
1286 intptr_t new_end_index = 0;
1287 uint16_t border = 0;
1290 &new_end_index, &border);
1294 if (border == last + 1) {
1297 above = (end_index & 1) != (start_index & 1) ? odd_label : even_label;
1298 ASSERT(new_end_index == end_index - 1);
1301 ASSERT(start_index <= new_end_index);
1302 ASSERT(new_start_index <= end_index);
1303 ASSERT(start_index < new_start_index);
1304 ASSERT(new_end_index < end_index);
1305 ASSERT(new_end_index + 1 == new_start_index ||
1306 (new_end_index + 2 == new_start_index &&
1307 border == ranges->
At(new_end_index + 1)));
1308 ASSERT(min_char < border - 1);
1309 ASSERT(border < max_char);
1310 ASSERT(ranges->
At(new_end_index) < border);
1311 ASSERT(border < ranges->At(new_start_index) ||
1312 (border == ranges->
At(new_start_index) &&
1313 new_start_index == end_index && new_end_index == end_index - 1 &&
1314 border == last + 1));
1315 ASSERT(new_start_index == 0 || border >= ranges->
At(new_start_index - 1));
1320 border - 1, &dummy, even_label, odd_label);
1324 bool flip = (new_start_index & 1) != (start_index & 1);
1325 GenerateBranches(masm, ranges, new_start_index, end_index, border, max_char,
1326 &dummy, flip ? odd_label : even_label,
1327 flip ? even_label : odd_label);
1351 intptr_t range_count = ranges->
length();
1353 intptr_t last_valid_range = range_count - 1;
1354 while (last_valid_range >= 0) {
1356 if (range.
from() <= max_char) {
1362 if (last_valid_range < 0) {
1363 if (!
cc->is_negated()) {
1364 macro_assembler->
GoTo(on_failure);
1372 if (last_valid_range == 0 && ranges->
At(0).IsEverything(max_char)) {
1373 if (
cc->is_negated()) {
1374 macro_assembler->
GoTo(on_failure);
1389 cc->standard_type(), on_failure)) {
1402 bool zeroth_entry_is_failure = !
cc->is_negated();
1404 for (intptr_t
i = 0;
i <= last_valid_range;
i++) {
1406 if (range.
from() == 0) {
1408 zeroth_entry_is_failure = !zeroth_entry_is_failure;
1410 range_boundaries->
Add(range.
from());
1412 if (range.
to() + 1 <= max_char) {
1413 range_boundaries->
Add(range.
to() + 1);
1416 intptr_t end_index = range_boundaries->
length() - 1;
1423 max_char, &fall_through,
1424 zeroth_entry_is_failure ? &fall_through : on_failure,
1425 zeroth_entry_is_failure ? on_failure : &fall_through);
1426 macro_assembler->
BindBlock(&fall_through);
1440 if (label_.is_bound()) {
1443 macro_assembler->
GoTo(&label_);
1450 macro_assembler->
GoTo(&label_);
1475 bool not_at_start) {
1476 if (budget <= 0)
return 0;
1477 if (action_type_ == POSITIVE_SUBMATCH_SUCCESS)
return 0;
1478 return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
1484 bool not_at_start) {
1485 if (action_type_ == BEGIN_SUBMATCH) {
1487 }
else if (action_type_ != POSITIVE_SUBMATCH_SUCCESS) {
1488 on_success()->FillInBMInfo(
offset, budget - 1, bm, not_at_start);
1490 SaveBMInfo(bm, not_at_start,
offset);
1495 bool not_at_start) {
1496 if (budget <= 0)
return 0;
1502 if (assertion_type() == AT_START && not_at_start)
return still_to_find;
1503 return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
1509 bool not_at_start) {
1511 if (assertion_type() == AT_START && not_at_start)
return;
1512 on_success()->FillInBMInfo(
offset, budget - 1, bm, not_at_start);
1513 SaveBMInfo(bm, not_at_start,
offset);
1518 bool not_at_start) {
1519 if (read_backward())
return 0;
1520 if (budget <= 0)
return 0;
1521 return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
1526 bool not_at_start) {
1527 if (read_backward())
return 0;
1528 intptr_t answer = Length();
1529 if (answer >= still_to_find)
return answer;
1530 if (budget <= 0)
return answer;
1533 on_success()->EatsAtLeast(still_to_find - answer, budget - 1,
true);
1538 bool not_at_start) {
1539 if (budget <= 0)
return 0;
1542 RegExpNode* node = (*alternatives_)[1].node();
1543 return node->
EatsAtLeast(still_to_find, budget - 1, not_at_start);
1550 bool not_at_start) {
1553 RegExpNode* node = (*alternatives_)[1].node();
1560 bool not_at_start) {
1561 if (budget <= 0)
return 0;
1563 intptr_t choice_count = alternatives_->length();
1564 budget = (budget - 1) / choice_count;
1565 for (intptr_t
i = 0;
i < choice_count;
i++) {
1567 if (node == ignore_this_node)
continue;
1568 intptr_t node_eats_at_least =
1569 node->
EatsAtLeast(still_to_find, budget, not_at_start);
1570 if (node_eats_at_least <
min)
min = node_eats_at_least;
1571 if (
min == 0)
return 0;
1578 bool not_at_start) {
1579 return EatsAtLeastHelper(still_to_find, budget - 1, loop_node_, not_at_start);
1584 bool not_at_start) {
1585 return EatsAtLeastHelper(still_to_find, budget,
nullptr, not_at_start);
1599 bool found_useful_op =
false;
1608 intptr_t char_shift = 0;
1609 for (intptr_t
i = 0;
i < characters_;
i++) {
1612 found_useful_op =
true;
1614 mask_ |= (
pos->mask & char_mask) << char_shift;
1615 value_ |= (
pos->value & char_mask) << char_shift;
1616 char_shift += asc ? 8 : 16;
1618 return found_useful_op;
1622 Trace* bounds_check_trace,
1624 bool preload_has_checked_bounds,
1627 bool fall_through_on_failure) {
1628 if (details->
characters() == 0)
return false;
1629 GetQuickCheckDetails(details,
compiler, 0,
1634 compiler->macro_assembler()->CanReadUnaligned());
1635 uint32_t mask = details->
mask();
1648 !preload_has_checked_bounds, details->
characters());
1651 bool need_mask =
true;
1662 if ((mask & char_mask) == char_mask) need_mask =
false;
1668 if ((mask & 0xffff) == 0xffff) need_mask =
false;
1670 if ((mask & 0xffff) == 0xffff) need_mask =
false;
1672 if (mask == 0xffffffff) need_mask =
false;
1676 if (fall_through_on_failure) {
1702 intptr_t characters_filled_in,
1703 bool not_at_start) {
1704#if defined(__GNUC__) && defined(__BYTE_ORDER__)
1707 (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__));
1711 if (read_backward())
return;
1712 ASSERT(characters_filled_in < details->characters());
1720 for (intptr_t k = 0; k < elms_->length(); k++) {
1724 for (intptr_t
i = 0;
i < characters &&
i < quarks->
length();
i++) {
1726 details->
positions(characters_filled_in);
1727 uint16_t c = quarks->
At(
i);
1728 if (c > char_mask) {
1736 pos->determines_perfectly =
false;
1748 pos->mask = char_mask;
1750 pos->determines_perfectly =
true;
1752 uint32_t common_bits = char_mask;
1753 uint32_t
bits = chars[0];
1754 for (intptr_t j = 1; j <
length; j++) {
1755 uint32_t differing_bits = ((chars[j] & common_bits) ^
bits);
1756 common_bits ^= differing_bits;
1757 bits &= common_bits;
1763 uint32_t one_zero = (common_bits | ~char_mask);
1764 if (
length == 2 && ((~one_zero) & ((~one_zero) - 1)) == 0) {
1765 pos->determines_perfectly =
true;
1767 pos->mask = common_bits;
1774 pos->mask = char_mask;
1776 pos->determines_perfectly =
true;
1778 characters_filled_in++;
1779 ASSERT(characters_filled_in <= details->characters());
1780 if (characters_filled_in == details->
characters()) {
1786 details->
positions(characters_filled_in);
1801 intptr_t first_range = 0;
1802 while (ranges->
At(first_range).from() > char_mask) {
1804 if (first_range == ranges->
length()) {
1806 pos->determines_perfectly =
false;
1811 uint16_t from = range.
from();
1812 uint16_t to = range.
to();
1813 if (to > char_mask) {
1816 uint32_t differing_bits = (from ^ to);
1819 if ((differing_bits & (differing_bits + 1)) == 0 &&
1820 from + differing_bits == to) {
1821 pos->determines_perfectly =
true;
1823 uint32_t common_bits = ~SmearBitsRight(differing_bits);
1824 uint32_t
bits = (from & common_bits);
1825 for (intptr_t
i = first_range + 1;
i < ranges->
length();
i++) {
1827 uint16_t from = range.
from();
1828 uint16_t to = range.
to();
1829 if (from > char_mask)
continue;
1830 if (to > char_mask) to = char_mask;
1836 pos->determines_perfectly =
false;
1837 uint32_t new_common_bits = (from ^ to);
1838 new_common_bits = ~SmearBitsRight(new_common_bits);
1839 common_bits &= new_common_bits;
1840 bits &= new_common_bits;
1841 uint32_t differing_bits = (from & common_bits) ^
bits;
1842 common_bits ^= differing_bits;
1843 bits &= common_bits;
1845 pos->mask = common_bits;
1848 characters_filled_in++;
1849 ASSERT(characters_filled_in <= details->characters());
1850 if (characters_filled_in == details->
characters()) {
1857 on_success()->GetQuickCheckDetails(details,
compiler, characters_filled_in,
1863 for (
int i = 0;
i < characters_;
i++) {
1864 positions_[
i].mask = 0;
1865 positions_[
i].value = 0;
1866 positions_[
i].determines_perfectly =
false;
1872 if (by >= characters_ || by < 0) {
1874 ASSERT(by >= 0 || characters_ == 0);
1878 for (intptr_t
i = 0;
i < characters_ - by;
i++) {
1879 positions_[
i] = positions_[by +
i];
1881 for (intptr_t
i = characters_ - by;
i < characters_;
i++) {
1882 positions_[
i].mask = 0;
1883 positions_[
i].value = 0;
1884 positions_[
i].determines_perfectly =
false;
1893 ASSERT(characters_ == other->characters_);
1894 if (other->cannot_match_) {
1897 if (cannot_match_) {
1901 for (intptr_t
i = from_index;
i < characters_;
i++) {
1908 pos->determines_perfectly =
false;
1913 uint16_t differing_bits = (
pos->value ^ other_pos->
value);
1914 pos->mask &= ~differing_bits;
1923 info->visited =
true;
1932 if (
info()->replacement_calculated)
return replacement();
1933 if (depth < 0)
return this;
1936 return FilterSuccessor(depth - 1);
1941 if (
next ==
nullptr)
return set_replacement(
nullptr);
1943 return set_replacement(
this);
1955 for (intptr_t
i = 0;
i < ranges->
length();
i++) {
1978 if (
info()->replacement_calculated)
return replacement();
1979 if (depth < 0)
return this;
1982 intptr_t element_count = elms_->length();
1983 for (intptr_t
i = 0;
i < element_count;
i++) {
1987 for (intptr_t j = 0; j < quarks->
length(); j++) {
1988 uint16_t c = quarks->
At(j);
1995 if (converted == 0)
return set_replacement(
nullptr);
1997 (*quarks)[0] = converted;
2007 intptr_t range_count = ranges->
length();
2008 if (
cc->is_negated()) {
2009 if (range_count != 0 && ranges->
At(0).from() == 0 &&
2012 if (
cc->flags().IgnoreCase() &&
2016 return set_replacement(
nullptr);
2019 if (range_count == 0 ||
2022 if (
cc->flags().IgnoreCase() &&
2025 return set_replacement(
nullptr);
2030 return FilterSuccessor(depth - 1);
2034 if (
info()->replacement_calculated)
return replacement();
2035 if (depth < 0)
return this;
2036 if (
info()->visited)
return this;
2043 if (continue_replacement ==
nullptr)
return set_replacement(
nullptr);
2050 if (
info()->replacement_calculated)
return replacement();
2051 if (depth < 0)
return this;
2052 if (
info()->visited)
return this;
2054 intptr_t choice_count = alternatives_->length();
2056 for (intptr_t
i = 0;
i < choice_count;
i++) {
2058 if (alternative.
guards() !=
nullptr &&
2059 alternative.
guards()->length() != 0) {
2060 set_replacement(
this);
2065 intptr_t surviving = 0;
2067 for (intptr_t
i = 0;
i < choice_count;
i++) {
2070 ASSERT(replacement !=
this);
2071 if (replacement !=
nullptr) {
2072 (*alternatives_)[
i].set_node(replacement);
2074 survivor = replacement;
2077 if (surviving < 2)
return set_replacement(survivor);
2079 set_replacement(
this);
2080 if (surviving == choice_count) {
2087 for (intptr_t
i = 0;
i < choice_count;
i++) {
2090 if (replacement !=
nullptr) {
2091 (*alternatives_)[
i].set_node(replacement);
2092 new_alternatives->
Add((*alternatives_)[
i]);
2095 alternatives_ = new_alternatives;
2100 if (
info()->replacement_calculated)
return replacement();
2101 if (depth < 0)
return this;
2102 if (
info()->visited)
return this;
2106 RegExpNode* node = (*alternatives_)[1].node();
2108 if (replacement ==
nullptr)
return set_replacement(
nullptr);
2109 (*alternatives_)[1].set_node(replacement);
2111 RegExpNode* neg_node = (*alternatives_)[0].node();
2115 if (neg_replacement ==
nullptr)
return set_replacement(replacement);
2116 (*alternatives_)[0].set_node(neg_replacement);
2117 return set_replacement(
this);
2122 intptr_t characters_filled_in,
2123 bool not_at_start) {
2124 if (body_can_be_zero_length_ ||
info()->visited)
return;
2127 characters_filled_in, not_at_start);
2133 bool not_at_start) {
2134 if (body_can_be_zero_length_ || budget <= 0) {
2136 SaveBMInfo(bm, not_at_start,
offset);
2140 SaveBMInfo(bm, not_at_start,
offset);
2145 intptr_t characters_filled_in,
2146 bool not_at_start) {
2147 not_at_start = (not_at_start || not_at_start_);
2148 intptr_t choice_count = alternatives_->length();
2149 ASSERT(choice_count > 0);
2150 (*alternatives_)[0].node()->GetQuickCheckDetails(
2151 details,
compiler, characters_filled_in, not_at_start);
2152 for (intptr_t
i = 1;
i < choice_count;
i++) {
2158 details->
Merge(&new_details, characters_filled_in);
2166 bool fall_through_on_word) {
2168 fall_through_on_word ?
'w' :
'W',
2169 fall_through_on_word ? non_word :
word)) {
2179 if (fall_through_on_word) {
2194 Trace new_trace(*trace);
2220void AssertionNode::EmitBoundaryCheck(RegExpCompiler*
compiler,
Trace* trace) {
2221 RegExpMacroAssembler* assembler =
compiler->macro_assembler();
2224 BoyerMooreLookahead* lookahead = bm_info(not_at_start);
2225 if (lookahead ==
nullptr) {
2226 intptr_t eats_at_least =
2230 if (eats_at_least >= 1) {
2231 BoyerMooreLookahead* bm =
2232 new (
Z) BoyerMooreLookahead(eats_at_least,
compiler,
Z);
2233 FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
2238 if (lookahead->at(0)->is_non_word())
2244 BlockLabel before_non_word;
2245 BlockLabel before_word;
2246 if (trace->characters_preloaded() != 1) {
2247 assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
2250 EmitWordCheck(assembler, &before_word, &before_non_word,
false);
2252 assembler->BindBlock(&before_non_word);
2256 BacktrackIfPrevious(
compiler, trace, at_boundary ? kIsNonWord : kIsWord);
2258 if (!assembler->IsClosed()) {
2259 assembler->GoTo(&
ok);
2262 assembler->BindBlock(&before_word);
2263 BacktrackIfPrevious(
compiler, trace, at_boundary ? kIsWord : kIsNonWord);
2264 assembler->BindBlock(&
ok);
2266 BacktrackIfPrevious(
compiler, trace, at_boundary ? kIsWord : kIsNonWord);
2269 BacktrackIfPrevious(
compiler, trace, at_boundary ? kIsNonWord : kIsWord);
2273void AssertionNode::BacktrackIfPrevious(
2276 AssertionNode::IfPrevious backtrack_if_previous) {
2277 RegExpMacroAssembler* assembler =
compiler->macro_assembler();
2278 Trace new_trace(*trace);
2279 new_trace.InvalidateCurrentCharacter();
2281 BlockLabel fall_through, dummy;
2283 BlockLabel* non_word = backtrack_if_previous == kIsNonWord
2284 ? new_trace.backtrack()
2286 BlockLabel*
word = backtrack_if_previous == kIsNonWord
2288 : new_trace.backtrack();
2290 if (new_trace.cp_offset() == 0) {
2293 assembler->CheckAtStart(non_word);
2297 assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy,
false);
2300 assembler->BindBlock(&fall_through);
2301 on_success()->Emit(
compiler, &new_trace);
2307 bool not_at_start) {
2308 if (assertion_type_ == AT_START && not_at_start) {
2312 return on_success()->GetQuickCheckDetails(details,
compiler, filled_in,
2318 switch (assertion_type_) {
2333 Trace at_start_trace = *trace;
2335 on_success()->Emit(
compiler, &at_start_trace);
2343 case AT_NON_BOUNDARY: {
2344 EmitBoundaryCheck(
compiler, trace);
2348 on_success()->Emit(
compiler, trace);
2352 if (quick_check ==
nullptr)
return false;
2358 if (index > *checked_up_to) {
2359 *checked_up_to = index;
2392void TextNode::TextEmitPass(RegExpCompiler*
compiler,
2393 TextEmitPassType pass,
2396 bool first_element_checked,
2397 intptr_t* checked_up_to) {
2398 RegExpMacroAssembler* assembler =
compiler->macro_assembler();
2399 bool one_byte =
compiler->one_byte();
2400 BlockLabel*
backtrack = trace->backtrack();
2401 QuickCheckDetails* quick_check = trace->quick_check_performed();
2402 intptr_t element_count = elms_->length();
2403 intptr_t backward_offset = read_backward() ? -Length() : 0;
2404 for (intptr_t
i = preloaded ? 0 : element_count - 1;
i >= 0;
i--) {
2405 TextElement elm = elms_->At(
i);
2406 intptr_t
cp_offset = trace->cp_offset() + elm.cp_offset() + backward_offset;
2408 ZoneGrowableArray<uint16_t>* quarks = elm.atom()->data();
2409 for (intptr_t j = preloaded ? 0 : quarks->length() - 1; j >= 0; j--) {
2410 if (SkipPass(pass, elm.atom()->ignore_case()))
continue;
2411 if (first_element_checked &&
i == 0 && j == 0)
continue;
2414 uint16_t quark = quarks->At(j);
2415 if (elm.atom()->ignore_case()) {
2422 case NON_LATIN1_MATCH:
2429 case NON_LETTER_CHARACTER_MATCH:
2432 case SIMPLE_CHARACTER_MATCH:
2435 case CASE_CHARACTER_MATCH:
2441 if (emit_function !=
nullptr) {
2442 const bool bounds_check =
2443 *checked_up_to < (
cp_offset + j) || read_backward();
2444 bool bound_checked =
2446 cp_offset + j, bounds_check, preloaded);
2452 if (pass == CHARACTER_CLASS_MATCH) {
2453 if (first_element_checked &&
i == 0)
continue;
2455 RegExpCharacterClass*
cc = elm.char_class();
2456 bool bounds_check = *checked_up_to <
cp_offset || read_backward();
2458 bounds_check, preloaded,
Z);
2465intptr_t TextNode::Length() {
2466 TextElement elm = elms_->Last();
2467 ASSERT(elm.cp_offset() >= 0);
2468 return elm.cp_offset() + elm.length();
2471bool TextNode::SkipPass(intptr_t intptr_t_pass,
bool ignore_case) {
2472 TextEmitPassType pass =
static_cast<TextEmitPassType
>(intptr_t_pass);
2474 return pass == SIMPLE_CHARACTER_MATCH;
2476 return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH;
2485 ASSERT(ranges !=
nullptr);
2488 return new TextNode(elms, read_backward, on_success);
2505 return new TextNode(elms, read_backward, on_success);
2516 if (limit_result == DONE)
return;
2517 ASSERT(limit_result == CONTINUE);
2526 TextEmitPass(
compiler, NON_LATIN1_MATCH,
false, trace,
false, &dummy);
2529 bool first_elt_done =
false;
2530 intptr_t bound_checked_to = trace->
cp_offset() - 1;
2536 for (intptr_t pass = kFirstRealPass; pass <= kLastPass; pass++) {
2537 TextEmitPass(
compiler,
static_cast<TextEmitPassType
>(pass),
true, trace,
2538 false, &bound_checked_to);
2540 first_elt_done =
true;
2543 for (intptr_t pass = kFirstRealPass; pass <= kLastPass; pass++) {
2544 TextEmitPass(
compiler,
static_cast<TextEmitPassType
>(pass),
false, trace,
2545 first_elt_done, &bound_checked_to);
2548 Trace successor_trace(*trace);
2551 read_backward() ? -Length() : Length(),
compiler);
2555 on_success()->Emit(
compiler, &successor_trace);
2559 characters_preloaded_ = 0;
2567 characters_preloaded_ = 0;
2577 bound_checked_up_to_ =
2578 Utils::Maximum(
static_cast<intptr_t
>(0), bound_checked_up_to_ - by);
2582 intptr_t element_count = elms_->length();
2583 for (intptr_t
i = 0;
i < element_count;
i++) {
2587 bool case_equivalents_already_added =
2588 cc->flags().NeedsUnicodeCaseEquivalents();
2589 if (
cc->flags().IgnoreCase() && !case_equivalents_already_added) {
2592 if (
cc->is_standard())
continue;
2606 if (read_backward())
return nullptr;
2607 if (elms_->length() != 1)
return nullptr;
2616 return ranges->
length() == 0 ? on_success() :
nullptr;
2618 if (ranges->
length() != 1)
return nullptr;
2625 return ranges->
At(0).IsEverything(max_char) ? on_success() :
nullptr;
2638 intptr_t recursion_depth = 0;
2639 while (node !=
this) {
2641 return kNodeIsTooComplexForGreedyLoops;
2644 if (node_length == kNodeIsTooComplexForGreedyLoops) {
2645 return kNodeIsTooComplexForGreedyLoops;
2655 ASSERT(loop_node_ ==
nullptr);
2656 AddAlternative(alt);
2657 loop_node_ = alt.
node();
2661 ASSERT(continue_node_ ==
nullptr);
2662 AddAlternative(alt);
2663 continue_node_ = alt.
node();
2670 intptr_t text_length =
2671 GreedyLoopTextLengthForAlternative(&alternatives_->At(0));
2672 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
2689 intptr_t eats_at_least) {
2690 intptr_t preload_characters =
2693#if !defined(DART_COMPRESSED_POINTERS) && !defined(TARGET_ARCH_RISCV32)
2694 if (preload_characters > 4) preload_characters = 4;
2698 if (preload_characters == 3) preload_characters = 2;
2702 if (preload_characters > 2) preload_characters = 2;
2705#if !defined(DART_COMPRESSED_POINTERS) && !defined(TARGET_ARCH_RISCV32)
2706 if (preload_characters > 2) preload_characters = 2;
2710 if (preload_characters > 1) preload_characters = 1;
2713 if (!
compiler->macro_assembler()->CanReadUnaligned()) {
2714 if (preload_characters > 1) preload_characters = 1;
2716 return preload_characters;
2723 : possible_success(),
2724 expects_preload(
false),
2726 quick_check_details() {}
2739 if (
count > kAFew) {
2748 return &a_few_alt_gens_[
i];
2750 return &excess_alt_gens_[
i - kAFew];
2754 static constexpr intptr_t kAFew = 10;
2758 std::unique_ptr<AlternativeGeneration[]> excess_alt_gens_;
2772 '\t',
'\r' + 1,
' ',
' ' + 1, 0x00A0, 0x00A1, 0x1680,
2773 0x1681, 0x2000, 0x200B, 0x2028, 0x202A, 0x202F, 0x2030,
2777 '0',
'9' + 1,
'A',
'Z' + 1,
'_',
'_' + 1,
'a',
'z' + 1,
kRangeEndMarker};
2798 if (interval.
to() - interval.
from() >= kMapSize - 1) {
2799 if (map_count_ != kMapSize) {
2800 map_count_ = kMapSize;
2801 for (intptr_t
i = 0;
i < kMapSize;
i++)
2806 for (intptr_t
i = interval.
from();
i <= interval.
to();
i++) {
2807 intptr_t mod_character = (
i & kMask);
2808 if (!map_->At(mod_character)) {
2810 (*map_)[mod_character] =
true;
2812 if (map_count_ == kMapSize)
return;
2818 if (map_count_ != kMapSize) {
2819 map_count_ = kMapSize;
2820 for (intptr_t
i = 0;
i < kMapSize;
i++)
2843bool BoyerMooreLookahead::FindWorthwhileInterval(intptr_t* from, intptr_t* to) {
2844 intptr_t biggest_points = 0;
2847 const intptr_t kMaxMax = 32;
2848 for (intptr_t max_number_of_chars = 4; max_number_of_chars < kMaxMax;
2849 max_number_of_chars *= 2) {
2851 FindBestInterval(max_number_of_chars, biggest_points, from, to);
2853 if (biggest_points == 0)
return false;
2863intptr_t BoyerMooreLookahead::FindBestInterval(intptr_t max_number_of_chars,
2864 intptr_t old_biggest_points,
2867 intptr_t biggest_points = old_biggest_points;
2869 for (intptr_t
i = 0;
i < length_;) {
2870 while (
i < length_ &&
Count(
i) > max_number_of_chars)
2872 if (
i == length_)
break;
2873 intptr_t remembered_from =
i;
2874 bool union_map[
kSize];
2875 for (intptr_t j = 0; j <
kSize; j++)
2876 union_map[j] =
false;
2877 while (
i < length_ &&
Count(
i) <= max_number_of_chars) {
2878 BoyerMoorePositionInfo*
map = bitmaps_->At(
i);
2879 for (intptr_t j = 0; j <
kSize; j++)
2880 union_map[j] |=
map->at(j);
2883 intptr_t frequency = 0;
2884 for (intptr_t j = 0; j <
kSize; j++) {
2899 bool in_quickcheck_range =
2900 ((
i - remembered_from < 4) ||
2901 (compiler_->
one_byte() ? remembered_from <= 4 : remembered_from <= 2));
2904 intptr_t probability =
2905 (in_quickcheck_range ?
kSize / 2 :
kSize) - frequency;
2906 intptr_t
points = (
i - remembered_from) * probability;
2907 if (
points > biggest_points) {
2908 *from = remembered_from;
2913 return biggest_points;
2921intptr_t BoyerMooreLookahead::GetSkipTable(
2922 intptr_t min_lookahead,
2923 intptr_t max_lookahead,
2924 const TypedData& boolean_skip_table) {
2927 const intptr_t kSkipArrayEntry = 0;
2928 const intptr_t kDontSkipArrayEntry = 1;
2930 for (intptr_t
i = 0;
i <
kSize;
i++) {
2931 boolean_skip_table.SetUint8(
i, kSkipArrayEntry);
2933 intptr_t
skip = max_lookahead + 1 - min_lookahead;
2935 for (intptr_t
i = max_lookahead;
i >= min_lookahead;
i--) {
2936 BoyerMoorePositionInfo*
map = bitmaps_->At(
i);
2937 for (intptr_t j = 0; j <
kSize; j++) {
2939 boolean_skip_table.SetUint8(j, kDontSkipArrayEntry);
2951 intptr_t min_lookahead = 0;
2952 intptr_t max_lookahead = 0;
2954 if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead))
return;
2956 bool found_single_character =
false;
2957 intptr_t single_character = 0;
2958 for (intptr_t
i = max_lookahead;
i >= min_lookahead;
i--) {
2960 if (
map->map_count() > 1 ||
2961 (found_single_character &&
map->map_count() != 0)) {
2962 found_single_character =
false;
2965 for (intptr_t j = 0; j < kSize; j++) {
2967 found_single_character =
true;
2968 single_character = j;
2974 intptr_t lookahead_width = max_lookahead + 1 - min_lookahead;
2976 if (found_single_character && lookahead_width == 1 && max_lookahead < 3) {
2981 if (found_single_character) {
2985 if (max_char_ > kSize) {
3000 intptr_t skip_distance =
3001 GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table);
3002 ASSERT(skip_distance != 0);
3096void ChoiceNode::AssertGuardsMentionRegisters(
Trace* trace) {
3099 for (intptr_t
i = 0;
i < choice_count - 1;
i++) {
3102 intptr_t guard_count = (guards ==
nullptr) ? 0 : guards->
length();
3103 for (intptr_t j = 0; j < guard_count; j++) {
3110void ChoiceNode::SetUpPreLoad(RegExpCompiler*
compiler,
3111 Trace* current_trace,
3112 PreloadState*
state) {
3115 state->eats_at_least_ =
3119 state->preload_characters_ =
3120 CalculatePreloadCharacters(
compiler,
state->eats_at_least_);
3122 state->preload_is_current_ =
3123 (current_trace->characters_preloaded() ==
state->preload_characters_);
3124 state->preload_has_checked_bounds_ =
state->preload_is_current_;
3130 if (choice_count == 1 &&
alternatives_->At(0).guards() ==
nullptr) {
3135 AssertGuardsMentionRegisters(trace);
3138 if (limit_result ==
DONE)
return;
3154 intptr_t text_length =
3159 trace = EmitGreedyLoop(
compiler, trace, &alt_gens, &preload,
3160 &greedy_loop_state, text_length);
3165 compiler->macro_assembler()->BindBlock(&second_choice);
3169 EmitChoices(
compiler, &alt_gens, 0, trace, &preload);
3175 intptr_t new_flush_budget = trace->
flush_budget() / choice_count;
3176 for (intptr_t
i = 0;
i < choice_count;
i++) {
3178 Trace new_trace(*trace);
3182 if (new_trace.
actions() !=
nullptr) {
3185 bool next_expects_preload =
3189 next_expects_preload);
3198 intptr_t text_length) {
3210 Trace greedy_match_trace;
3214 macro_assembler->
BindBlock(&loop_label);
3218 (*alternatives_)[0].node()->Emit(
compiler, &greedy_match_trace);
3219 macro_assembler->
BindBlock(&greedy_match_failed);
3222 macro_assembler->
BindBlock(&second_choice);
3226 EmitChoices(
compiler, alt_gens, 1, new_trace, preload);
3233 macro_assembler->
GoTo(&second_choice);
3237intptr_t ChoiceNode::EmitOptimizedUnanchoredSearch(RegExpCompiler*
compiler,
3243 if (alt1.guards() !=
nullptr && alt1.guards()->length() != 0) {
3244 return eats_at_least;
3246 RegExpNode* eats_anything_node = alt1.node();
3247 if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(
compiler) !=
this) {
3248 return eats_at_least;
3257 ASSERT(trace->is_trivial());
3259 RegExpMacroAssembler* macro_assembler =
compiler->macro_assembler();
3267 BoyerMooreLookahead* bm =
bm_info(
false);
3268 if (bm ==
nullptr) {
3272 if (eats_at_least >= 1) {
3273 bm =
new (
Z) BoyerMooreLookahead(eats_at_least,
compiler,
Z);
3278 if (bm !=
nullptr) {
3279 bm->EmitSkipInstructions(macro_assembler);
3281 return eats_at_least;
3284void ChoiceNode::EmitChoices(RegExpCompiler*
compiler,
3285 AlternativeGenerationList* alt_gens,
3286 intptr_t first_choice,
3288 PreloadState* preload) {
3289 RegExpMacroAssembler* macro_assembler =
compiler->macro_assembler();
3290 SetUpPreLoad(
compiler, trace, preload);
3296 intptr_t new_flush_budget = trace->flush_budget() / choice_count;
3298 for (intptr_t
i = first_choice;
i < choice_count;
i++) {
3299 bool is_last =
i == choice_count - 1;
3300 bool fall_through_on_failure = !is_last;
3302 AlternativeGeneration* alt_gen = alt_gens->at(
i);
3303 alt_gen->quick_check_details.set_characters(preload->preload_characters_);
3304 ZoneGrowableArray<Guard*>* guards = alternative.guards();
3305 intptr_t guard_count = (guards ==
nullptr) ? 0 : guards->
length();
3306 Trace new_trace(*trace);
3308 preload->preload_is_current_ ? preload->preload_characters_ : 0);
3309 if (preload->preload_has_checked_bounds_) {
3317 alt_gen->expects_preload = preload->preload_is_current_;
3318 bool generate_full_check_inline =
false;
3321 alternative.node()->EmitQuickCheck(
3322 compiler, trace, &new_trace, preload->preload_has_checked_bounds_,
3323 &alt_gen->possible_success, &alt_gen->quick_check_details,
3324 fall_through_on_failure)) {
3326 preload->preload_is_current_ =
true;
3327 preload->preload_has_checked_bounds_ =
true;
3330 if (!fall_through_on_failure) {
3331 macro_assembler->BindBlock(&alt_gen->possible_success);
3335 generate_full_check_inline =
true;
3337 }
else if (alt_gen->quick_check_details.cannot_match()) {
3338 if (!fall_through_on_failure) {
3339 macro_assembler->GoTo(trace->backtrack());
3348 if (
i != first_choice) {
3349 alt_gen->expects_preload =
false;
3352 generate_full_check_inline =
true;
3354 if (generate_full_check_inline) {
3355 if (new_trace.
actions() !=
nullptr) {
3358 for (intptr_t j = 0; j < guard_count; j++) {
3359 GenerateGuard(macro_assembler, guards->At(j), &new_trace);
3361 alternative.node()->Emit(
compiler, &new_trace);
3362 preload->preload_is_current_ =
false;
3364 macro_assembler->BindBlock(&alt_gen->after);
3368void ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler*
compiler,
3370 GuardedAlternative alternative,
3371 AlternativeGeneration* alt_gen,
3372 intptr_t preload_characters,
3373 bool next_expects_preload) {
3374 if (!alt_gen->possible_success.is_linked())
return;
3376 RegExpMacroAssembler* macro_assembler =
compiler->macro_assembler();
3377 macro_assembler->BindBlock(&alt_gen->possible_success);
3378 Trace out_of_line_trace(*trace);
3379 out_of_line_trace.set_characters_preloaded(preload_characters);
3380 out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details);
3382 ZoneGrowableArray<Guard*>* guards = alternative.guards();
3383 intptr_t guard_count = (guards ==
nullptr) ? 0 : guards->length();
3384 if (next_expects_preload) {
3385 BlockLabel reload_current_char;
3386 out_of_line_trace.set_backtrack(&reload_current_char);
3387 for (intptr_t j = 0; j < guard_count; j++) {
3388 GenerateGuard(macro_assembler, guards->At(j), &out_of_line_trace);
3390 alternative.node()->Emit(
compiler, &out_of_line_trace);
3391 macro_assembler->BindBlock(&reload_current_char);
3395 macro_assembler->LoadCurrentCharacter(trace->cp_offset(),
nullptr,
false,
3396 preload_characters);
3397 macro_assembler->GoTo(&(alt_gen->after));
3399 out_of_line_trace.set_backtrack(&(alt_gen->after));
3400 for (intptr_t j = 0; j < guard_count; j++) {
3401 GenerateGuard(macro_assembler, guards->At(j), &out_of_line_trace);
3403 alternative.node()->Emit(
compiler, &out_of_line_trace);
3410 if (limit_result ==
DONE)
return;
3415 switch (action_type_) {
3418 data_.u_position_register.is_capture,
3420 Trace new_trace = *trace;
3427 data_.u_increment_register.reg);
3428 Trace new_trace = *trace;
3435 data_.u_store_register.value);
3436 Trace new_trace = *trace;
3443 data_.u_clear_captures.range_from, data_.u_clear_captures.range_to));
3444 Trace new_trace = *trace;
3454 data_.u_submatch.current_position_register, 0);
3456 data_.u_submatch.stack_pointer_register);
3461 intptr_t start_pos_reg = data_.u_empty_match_check.start_register;
3462 intptr_t stored_pos = 0;
3463 intptr_t rep_reg = data_.u_empty_match_check.repetition_register;
3466 if (know_dist && !has_minimum && stored_pos == trace->
cp_offset()) {
3470 }
else if (know_dist && stored_pos < trace->cp_offset()) {
3481 intptr_t limit = data_.u_empty_match_check.repetition_limit;
3482 assembler->
IfRegisterLT(rep_reg, limit, &skip_empty_check);
3488 assembler->
BindBlock(&skip_empty_check);
3499 data_.u_submatch.current_position_register);
3501 data_.u_submatch.stack_pointer_register);
3507 intptr_t clear_registers_from = data_.u_submatch.clear_register_from;
3509 Trace new_trace = *trace;
3513 assembler->
BindBlock(&clear_registers_backtrack);
3514 intptr_t clear_registers_to =
3516 assembler->
ClearRegisters(clear_registers_from, clear_registers_to);
3535 if (limit_result ==
DONE)
return;
3540 ASSERT(start_reg_ + 1 == end_reg_);
3566 explicit DotPrinter(
bool ignore_case) {}
3567 void PrintNode(
const char* label, RegExpNode* node);
3568 void Visit(RegExpNode* node);
3569 void PrintAttributes(RegExpNode* from);
3570 void PrintOnFailure(RegExpNode* from, RegExpNode* to);
3571#define DECLARE_VISIT(Type) virtual void Visit##Type(Type##Node* that);
3576void DotPrinter::PrintNode(
const char* label, RegExpNode* node) {
3578 for (intptr_t
i = 0; label[
i] !=
'\0';
i++) {
3596void DotPrinter::Visit(RegExpNode* node) {
3597 if (node->info()->visited)
return;
3598 node->info()->visited =
true;
3602void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
3603 OS::PrintErr(
" n%p -> n%p [style=dotted];\n", from, on_failure);
3607class AttributePrinter :
public ValueObject {
3609 AttributePrinter() : first_(
true) {}
3610 void PrintSeparator() {
3617 void PrintBit(
const char*
name,
bool value) {
3622 void PrintPositive(
const char*
name, intptr_t
value) {
3623 if (
value < 0)
return;
3632void DotPrinter::PrintAttributes(RegExpNode* that) {
3634 " a%p [shape=Mrecord, color=grey, fontcolor=grey, "
3635 "margin=0.1, fontsize=10, label=\"{",
3637 AttributePrinter printer;
3638 NodeInfo*
info = that->info();
3639 printer.PrintBit(
"NI",
info->follows_newline_interest);
3640 printer.PrintBit(
"WI",
info->follows_word_interest);
3641 printer.PrintBit(
"SI",
info->follows_start_interest);
3642 BlockLabel* label = that->label();
3643 if (label->is_bound()) printer.PrintPositive(
"@", label->pos());
3646 " a%p -> n%p [style=dashed, color=grey, arrowhead=none];\n",
3650void DotPrinter::VisitChoice(ChoiceNode* that) {
3651 OS::PrintErr(
" n%p [shape=Mrecord, label=\"?\"];\n", that);
3652 for (intptr_t
i = 0;
i < that->alternatives()->
length();
i++) {
3653 GuardedAlternative alt = that->alternatives()->At(
i);
3656 for (intptr_t
i = 0;
i < that->alternatives()->
length();
i++) {
3657 GuardedAlternative alt = that->alternatives()->At(
i);
3658 alt.node()->Accept(
this);
3662void DotPrinter::VisitText(TextNode* that) {
3664 for (intptr_t
i = 0;
i < that->elements()->
length();
i++) {
3666 TextElement elm = that->elements()->At(
i);
3667 switch (elm.text_type()) {
3669 ZoneGrowableArray<uint16_t>*
data = elm.atom()->data();
3670 for (intptr_t
i = 0;
i <
data->length();
i++) {
3676 RegExpCharacterClass* node = elm.char_class();
3679 for (intptr_t j = 0; j < node->ranges()->
length(); j++) {
3680 CharacterRange range = node->ranges()->At(j);
3693 PrintAttributes(that);
3694 OS::PrintErr(
" n%p -> n%p;\n", that, that->on_success());
3695 Visit(that->on_success());
3698void DotPrinter::VisitBackReference(BackReferenceNode* that) {
3699 OS::PrintErr(
" n%p [label=\"$%" Pd "..$%" Pd "\", shape=doubleoctagon];\n",
3700 that, that->start_register(), that->end_register());
3701 PrintAttributes(that);
3702 OS::PrintErr(
" n%p -> n%p;\n", that, that->on_success());
3703 Visit(that->on_success());
3706void DotPrinter::VisitEnd(EndNode* that) {
3707 OS::PrintErr(
" n%p [style=bold, shape=point];\n", that);
3708 PrintAttributes(that);
3711void DotPrinter::VisitAssertion(AssertionNode* that) {
3713 switch (that->assertion_type()) {
3731 PrintAttributes(that);
3732 RegExpNode* successor = that->on_success();
3737void DotPrinter::VisitAction(ActionNode* that) {
3739 switch (that->action_type_) {
3742 that->data_.u_store_register.reg,
3743 that->data_.u_store_register.value);
3747 that->data_.u_increment_register.reg);
3751 that->data_.u_position_register.reg);
3755 that->data_.u_submatch.current_position_register);
3762 that->data_.u_empty_match_check.start_register,
3763 that->data_.u_empty_match_check.repetition_register,
3764 that->data_.u_empty_match_check.repetition_limit);
3768 that->data_.u_clear_captures.range_from,
3769 that->data_.u_clear_captures.range_to);
3774 PrintAttributes(that);
3775 RegExpNode* successor = that->on_success();
3783 DotPrinter printer(ignore_case);
3784 printer.PrintNode(label, node);
3793#define OZ (on_success->zone())
3807 for (intptr_t
i = 0;
i <
elements()->length();
i++) {
3814 const int32_t* special_class,
3820 ASSERT(special_class[0] != 0);
3825 if (range.
from() != 0) {
3828 for (intptr_t
i = 0;
i <
length;
i += 2) {
3829 if (special_class[
i] != (range.
to() + 1)) {
3832 range = ranges->
At((
i >> 1) + 1);
3833 if (special_class[
i + 1] != range.
from()) {
3844 const int32_t* special_class,
3851 for (intptr_t
i = 0;
i <
length;
i += 2) {
3853 if (range.
from() != special_class[
i] ||
3854 range.
to() != special_class[
i + 1] - 1) {
3905 lead_surrogates_(nullptr),
3906 trail_surrogates_(nullptr),
3918 for (intptr_t
i = 0;
i <
base->length();
i++) {
3923 kBmpCodePoints, zone_);
3926 kLeadSurrogates, zone_);
3929 kTrailSurrogates, zone_);
3932 kBmpCodePoints, zone_);
3935 kNonBmpCodePoints, zone_);
3941 if (!
outset->Get(kBase))
return;
3943 if (
outset->Get(kBmpCodePoints)) {
3945 }
else if (
outset->Get(kLeadSurrogates)) {
3946 target = &lead_surrogates_;
3947 }
else if (
outset->Get(kTrailSurrogates)) {
3948 target = &trail_surrogates_;
3953 if (*
target ==
nullptr) {
3964 if (bmp ==
nullptr)
return;
3974 if (non_bmp ==
nullptr)
return;
3977 for (
int i = 0;
i < non_bmp->
length();
i++) {
3983 uint32_t from = non_bmp->
At(
i).from();
3984 uint32_t to = non_bmp->
At(
i).to();
3985 uint16_t from_points[2];
3987 uint16_t to_points[2];
3989 if (from_points[0] == to_points[0]) {
4017 if (from_points[0] <= to_points[0]) {
4039 int stack_register =
compiler->UnicodeLookaroundStackRegister();
4040 int position_register =
compiler->UnicodeLookaroundPositionRegister();
4045 return lookaround.
ForMatch(negative_match);
4055 int stack_register =
compiler->UnicodeLookaroundStackRegister();
4056 int position_register =
compiler->UnicodeLookaroundPositionRegister();
4070 if (lead_surrogates ==
nullptr)
return;
4081 compiler, trail_surrogates, lead_surrogates, on_success,
true,
4087 compiler, lead_surrogates, trail_surrogates, on_success,
false,
4098 if (trail_surrogates ==
nullptr)
return;
4109 compiler, trail_surrogates, lead_surrogates, on_success,
true,
4115 compiler, lead_surrogates, trail_surrogates, on_success,
false,
4148 icu::UnicodeSet
set;
4149 for (
int i = 0;
i < ranges->
length();
i++) {
4150 set.add(ranges->
At(
i).from(), ranges->
At(
i).to());
4153 set.closeOver(USET_CASE_INSENSITIVE);
4157 set.removeAllStrings();
4158 for (
int i = 0;
i <
set.getRangeCount();
i++) {
4181 if (
ranges->length() == 0) {
4211 result->AddAlternative(alternative);
4228 saved_expansion_factor_(
compiler->current_expansion_factor()),
4231 if (ok_to_expand_) {
4234 ok_to_expand_ =
false;
4237 intptr_t new_factor = saved_expansion_factor_ * factor;
4239 compiler->set_current_expansion_factor(new_factor);
4252 intptr_t saved_expansion_factor_;
4264 bool not_at_start) {
4286 const intptr_t kMaxUnrolledMinMatches = 3;
4288 const intptr_t kMaxUnrolledMaxMatches = 3;
4289 if (
max == 0)
return on_success;
4293 bool needs_capture_clearing = !capture_registers.
is_empty();
4296 if (body_can_be_empty) {
4297 body_start_reg =
compiler->AllocateRegister();
4312 for (intptr_t
i = 0;
i <
min;
i++) {
4318 if (
max <= kMaxUnrolledMaxMatches &&
min == 0) {
4324 for (intptr_t
i = 0;
i <
max;
i++) {
4335 answer = alternation;
4336 if (not_at_start && !
compiler->read_backward()) {
4344 bool has_min =
min > 0;
4346 bool needs_counter = has_min || has_max;
4347 intptr_t reg_ctr = needs_counter ?
compiler->AllocateRegister()
4351 if (not_at_start && !
compiler->read_backward()) center->set_not_at_start();
4356 if (body_can_be_empty) {
4363 if (body_can_be_empty) {
4368 if (needs_capture_clearing) {
4375 body_alt.
AddGuard(body_guard, zone);
4380 rest_alt.
AddGuard(rest_guard, zone);
4383 center->AddLoopAlternative(body_alt);
4384 center->AddContinueAlternative(rest_alt);
4386 center->AddContinueAlternative(rest_alt);
4387 center->AddLoopAlternative(body_alt);
4389 if (needs_counter) {
4407 int stack_register =
compiler->UnicodeLookaroundStackRegister();
4408 int position_register =
compiler->UnicodeLookaroundPositionRegister();
4412 for (
int i = 0;
i < 2;
i++) {
4413 bool lookbehind_for_word =
i == 0;
4414 bool lookahead_for_word =
4418 stack_register, position_register);
4420 word_range,
true, lookbehind.on_match_success(),
flags);
4423 lookbehind.ForMatch(backward),
4424 stack_register, position_register);
4426 word_range,
false, lookahead.on_match_success(),
flags);
4447 ? BoundaryAssertionAsLookaround(
compiler, on_success,
4456 intptr_t stack_pointer_register =
compiler->AllocateRegister();
4457 intptr_t position_register =
compiler->AllocateRegister();
4469 stack_pointer_register, position_register,
4475 stack_pointer_register, position_register, newline_matcher);
4478 result->AddAlternative(eol_alternative);
4480 result->AddAlternative(end_alternative);
4493 compiler->read_backward(), on_success);
4503 intptr_t stack_pointer_register,
4504 intptr_t position_register,
4505 intptr_t capture_register_count,
4506 intptr_t capture_register_start)
4507 : is_positive_(is_positive),
4508 on_success_(on_success),
4509 stack_pointer_register_(stack_pointer_register),
4510 position_register_(position_register) {
4513 stack_pointer_register, position_register, capture_register_count,
4514 capture_register_start, on_success);
4517 stack_pointer_register, position_register, capture_register_count,
4518 capture_register_start,
OZ);
4525 position_register_,
match);
4527 Zone* zone = on_success_->zone();
4536 position_register_, choice_node);
4542 intptr_t stack_pointer_register =
compiler->AllocateRegister();
4543 intptr_t position_register =
compiler->AllocateRegister();
4545 const intptr_t registers_per_capture = 2;
4546 const intptr_t register_of_first_capture = 2;
4547 intptr_t register_count = capture_count_ * registers_per_capture;
4548 intptr_t register_start =
4549 register_of_first_capture + capture_from_ * registers_per_capture;
4552 bool was_reading_backward =
compiler->read_backward();
4555 position_register, register_count, register_start);
4558 compiler->set_read_backward(was_reading_backward);
4575 intptr_t tmp = end_reg;
4576 end_reg = start_reg;
4589 for (intptr_t
i = 0;
i < children->
length();
i++) {
4590 current = children->
At(
i)->ToNode(
compiler, current);
4593 for (intptr_t
i = children->
length() - 1;
i >= 0;
i--) {
4594 current = children->
At(
i)->ToNode(
compiler, current);
4605 for (intptr_t
i = 0;
i < elmc;
i += 2) {
4616 ASSERT(elmv[0] != 0x0000);
4618 uint16_t last = 0x0000;
4619 for (intptr_t
i = 0;
i < elmc;
i += 2) {
4630 bool add_unicode_case_equivalents) {
4631 if (add_unicode_case_equivalents && (
type ==
'w' ||
type ==
'W')) {
4643 new_ranges = negated;
4648 AddClassEscape(
type, ranges);
4696 int range_count = ranges->
length();
4697 for (intptr_t
i = 0;
i < range_count;
i++) {
4699 int32_t bottom = range.
from();
4717 if (top == bottom) {
4719 intptr_t
length = jsregexp_uncanonicalize.
get(bottom,
'\0', chars);
4721 int32_t chr = chars[
i];
4722 if (chr != bottom) {
4746 intptr_t
pos = bottom;
4747 while (
pos <= top) {
4748 intptr_t
length = jsregexp_canonrange.
get(
pos,
'\0', range);
4754 block_end = range[0];
4756 intptr_t
end = (block_end > top) ? top : block_end;
4757 length = jsregexp_uncanonicalize.
get(block_end,
'\0', range);
4759 int32_t c = range[
i];
4760 int32_t range_from = c - (block_end -
pos);
4761 int32_t range_to = c - (block_end -
end);
4762 if (!(bottom <= range_from && range_to <= top)) {
4773 ASSERT(ranges !=
nullptr);
4774 intptr_t n = ranges->
length();
4775 if (n <= 1)
return true;
4776 intptr_t
max = ranges->
At(0).to();
4777 for (intptr_t
i = 1;
i < n;
i++) {
4779 if (next_range.
from() <=
max + 1)
return false;
4780 max = next_range.
to();
4786 if (ranges_ ==
nullptr) {
4801 for (intptr_t
i =
count - 1;
i >= 0;
i--) {
4802 (*list)[to +
i] = list->
At(from +
i);
4805 for (intptr_t
i = 0;
i <
count;
i++) {
4806 (*list)[to +
i] = list->
At(from +
i);
4820 int32_t from = insert.
from();
4821 int32_t to = insert.
to();
4822 intptr_t start_pos = 0;
4823 intptr_t end_pos =
count;
4824 for (intptr_t
i =
count - 1;
i >= 0;
i--) {
4826 if (current.
from() > to + 1) {
4828 }
else if (current.
to() + 1 < from) {
4841 if (start_pos == end_pos) {
4843 if (start_pos <
count) {
4846 (*list)[start_pos] = insert;
4849 if (start_pos + 1 == end_pos) {
4862 if (end_pos <
count) {
4866 return count - (end_pos - start_pos) + 1;
4872 if (ranges_ ==
nullptr)
return;
4878 if (character_ranges->
length() <= 1)
return;
4881 intptr_t n = character_ranges->
length();
4882 intptr_t
max = character_ranges->
At(0).to();
4886 if (current.
from() <=
max + 1) {
4901 intptr_t num_canonical =
i;
4904 character_ranges->
At(
read));
4916 intptr_t range_count = ranges->
length();
4919 if (range_count > 0 && ranges->
At(0).from() == 0) {
4920 from = ranges->
At(0).to();
4923 while (
i < range_count) {
4939 for (intptr_t
i = 0;
i < array->
length();
i++) {
4949 if (successors() !=
nullptr) {
4950 for (
int i = 0;
i < successors()->length();
i++) {
4951 OutSet* successor = successors()->At(
i);
4952 if (successor->
Get(
value))
return successor;
4959 successors()->Add(
result);
4963void OutSet::Set(
unsigned value,
Zone* zone) {
4964 if (
value < kFirstLimit) {
4965 first_ |= (1 <<
value);
4967 if (remaining_ ==
nullptr)
4968 remaining_ =
new (zone) ZoneGrowableArray<unsigned>(1);
4971 if (remaining_->is_empty() || !remaining_contains_value) {
4972 remaining_->Add(
value);
4978 if (
value < kFirstLimit) {
4979 return (first_ & (1 <<
value)) != 0;
4980 }
else if (remaining_ ==
nullptr) {
4996 bool inserted = tree()->
Insert(current.
from(), &loc);
5006 if (tree()->FindGreatestLessThan(current.
from(), &loc)) {
5007 Entry* entry = &loc.value();
5012 if (entry->
from() < current.
from() && entry->
to() >= current.
from()) {
5020 entry->
set_to(left.to());
5025 bool inserted = tree()->
Insert(right.from(), &loc);
5028 loc.set_value(
Entry(right.from(), right.to(), entry->
out_set()));
5032 if (tree()->FindLeastGreaterThan(current.
from(), &loc) &&
5033 (loc.value().from() <= current.
to()) &&
5034 (loc.value().to() >= current.
from())) {
5035 Entry* entry = &loc.value();
5039 if (current.
from() < entry->
from()) {
5041 bool inserted = tree()->
Insert(current.
from(), &ins);
5051 if (entry->
to() > current.
to()) {
5053 bool inserted = tree()->
Insert(current.
to() + 1, &ins);
5069 bool inserted = tree()->
Insert(current.
from(), &ins);
5081 if (!tree()->FindGreatestLessThan(
value, &loc))
return empty();
5082 Entry* entry = &loc.value();
5083 if (value <= entry->to())
5100void Analysis::VisitEnd(
EndNode* that) {
5105 intptr_t element_count = elements()->length();
5108 intptr_t cp_offset = 0;
5109 for (intptr_t
i = 0;
i < element_count;
i++) {
5112 cp_offset += elm.
length();
5116void Analysis::VisitText(
TextNode* that) {
5119 if (!has_failed()) {
5124void Analysis::VisitAction(ActionNode* that) {
5125 RegExpNode*
target = that->on_success();
5127 if (!has_failed()) {
5130 that->info()->AddFromFollowing(
target->info());
5134void Analysis::VisitChoice(ChoiceNode* that) {
5135 NodeInfo*
info = that->info();
5136 for (intptr_t
i = 0;
i < that->alternatives()->
length();
i++) {
5137 RegExpNode* node = (*that->alternatives())[
i].node();
5138 EnsureAnalyzed(node);
5139 if (has_failed())
return;
5142 info->AddFromFollowing(node->info());
5151 EnsureAnalyzed(node);
5152 if (has_failed())
return;
5153 info->AddFromFollowing(node->
info());
5159 if (!has_failed()) {
5168void Analysis::VisitAssertion(AssertionNode* that) {
5169 EnsureAnalyzed(that->on_success());
5175 bool not_at_start) {
5179 SaveBMInfo(bm, not_at_start,
offset);
5188 bool not_at_start) {
5190 budget = (budget - 1) / alts->
length();
5191 for (intptr_t
i = 0;
i < alts->
length();
i++) {
5193 if (alt.
guards() !=
nullptr && alt.
guards()->length() != 0) {
5195 SaveBMInfo(bm, not_at_start,
offset);
5200 SaveBMInfo(bm, not_at_start,
offset);
5206 bool not_at_start) {
5207 if (initial_offset >= bm->
length())
return;
5208 intptr_t
offset = initial_offset;
5209 intptr_t max_char = bm->
max_char();
5210 for (intptr_t
i = 0;
i < elements()->length();
i++) {
5212 if (initial_offset == 0) set_bm_info(not_at_start, bm);
5218 for (intptr_t j = 0; j < atom->
length(); j++,
offset++) {
5220 if (initial_offset == 0) set_bm_info(not_at_start, bm);
5229 for (intptr_t j = 0; j <
length; j++) {
5243 for (intptr_t k = 0; k < ranges->
length(); k++) {
5245 if (range.
from() > max_char)
continue;
5255 if (initial_offset == 0) set_bm_info(not_at_start, bm);
5260 if (initial_offset == 0) set_bm_info(not_at_start, bm);
5280 int stack_register =
compiler->UnicodeLookaroundStackRegister();
5281 int position_register =
compiler->UnicodeLookaroundPositionRegister();
5283 lead_surrogates,
true, on_success,
flags);
5285 stack_register, position_register);
5287 trail_surrogates,
false,
builder.on_match_success(),
5294 return optional_step_back;
5297#if !defined(DART_PRECOMPILED_RUNTIME)
5303 ASSERT(!FLAG_interpret_irregexp);
5307 const intptr_t specialization_cid =
function.string_specialization_cid();
5308 const bool is_sticky =
function.is_sticky_specialization();
5309 const bool is_one_byte = (specialization_cid == kOneByteStringCid);
5335 const bool is_end_anchored =
data->tree->IsAnchoredAtEnd();
5336 const bool is_start_anchored =
data->tree->IsAnchoredAtStart();
5337 intptr_t max_length =
data->tree->max_match();
5338 if (!is_start_anchored && !is_sticky) {
5344 captured_body,
data->contains_anchor);
5346 if (
data->contains_anchor) {
5353 false, loop_node)));
5354 node = first_step_node;
5363 if (node !=
nullptr) {
5366 }
else if (is_unicode && (is_global || is_sticky)) {
5383 parsed_function, ic_data_array, osr_id, zone);
5387 const intptr_t kMaxBacksearchLimit = 1024;
5388 if (is_end_anchored && !is_start_anchored && !is_sticky &&
5389 max_length < kMaxBacksearchLimit) {
5395 if (
data->tree->min_match() > 0) {
5397 }
else if (is_unicode) {
5404 compiler.Assemble(macro_assembler, node,
data->capture_count, pattern);
5406 if (FLAG_trace_irregexp) {
5420 ASSERT(FLAG_interpret_irregexp);
5445 bool is_end_anchored =
data->tree->IsAnchoredAtEnd();
5446 bool is_start_anchored =
data->tree->IsAnchoredAtStart();
5447 intptr_t max_length =
data->tree->max_match();
5448 if (!is_start_anchored && !is_sticky) {
5454 captured_body,
data->contains_anchor);
5456 if (
data->contains_anchor) {
5463 false, loop_node)));
5464 node = first_step_node;
5473 if (node !=
nullptr) {
5476 }
else if (is_unicode && (is_global || is_sticky)) {
5497 const intptr_t kMaxBacksearchLimit = 1024;
5498 if (is_end_anchored && !is_start_anchored && !is_sticky &&
5499 max_length < kMaxBacksearchLimit) {
5505 if (
data->tree->min_match() > 0) {
5507 }
else if (is_unicode) {
5514 compiler.Assemble(macro_assembler, node,
data->capture_count, pattern);
5516 if (FLAG_trace_irregexp) {
5526 intptr_t specialization_cid,
5536 UntaggedFunction::kIrregexpFunction,
5551 Object::dynamic_type());
5555 Object::dynamic_type());
5557 Symbols::string_param());
5559 Object::dynamic_type());
5561 Symbols::start_index_param());
5568 fn.set_is_debuggable(
false);
5587 if (!FLAG_interpret_irregexp) {
5589 const Class& owner =
5592 for (intptr_t
cid = kOneByteStringCid;
cid <= kTwoByteStringCid;
cid++) {
5600 return regexp.
ptr();
static void fail(const SkString &err)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static constexpr uint64_t kBits
static const int points[]
static void is_empty(skiatest::Reporter *reporter, const SkPath &p)
static float next(float f)
static const char marker[]
#define check(reporter, ref, unref, make, kill)
static bool read(SkStream *stream, void *buffer, size_t amount)
static bool skip(SkStream *stream, size_t amount)
static bool ok(int result)
intptr_t clear_register_count
static ActionNode * BeginSubmatch(intptr_t stack_pointer_reg, intptr_t position_reg, RegExpNode *on_success)
static ActionNode * EmptyMatchCheck(intptr_t start_register, intptr_t repetition_register, intptr_t repetition_limit, RegExpNode *on_success)
@ POSITIVE_SUBMATCH_SUCCESS
static ActionNode * SetRegister(intptr_t reg, intptr_t val, RegExpNode *on_success)
static ActionNode * PositiveSubmatchSuccess(intptr_t stack_pointer_reg, intptr_t restore_reg, intptr_t clear_capture_count, intptr_t clear_capture_from, RegExpNode *on_success)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
static ActionNode * IncrementRegister(intptr_t reg, RegExpNode *on_success)
static ActionNode * ClearCaptures(Interval range, RegExpNode *on_success)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
static ActionNode * StorePosition(intptr_t reg, bool is_capture, RegExpNode *on_success)
AlternativeGenerationList(intptr_t count)
AlternativeGeneration * at(intptr_t i)
void EnsureAnalyzed(RegExpNode *node)
const char * error_message()
virtual void VisitLoopChoice(LoopChoiceNode *that)
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
static AssertionNode * AfterNewline(RegExpNode *on_success)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
static AssertionNode * AtNonBoundary(RegExpNode *on_success)
static AssertionNode * AtStart(RegExpNode *on_success)
static AssertionNode * AtEnd(RegExpNode *on_success)
static AssertionNode * AtBoundary(RegExpNode *on_success)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t filled_in, bool not_at_start)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t recursion_depth, bool not_at_start)
void TruncateTo(intptr_t length)
void AddArray(const BaseGrowableArray< T, B, Allocator > &src)
const T & At(intptr_t index) const
Convenience wrapper around a BlockEntryInstr pointer.
void SetAll(intptr_t map_number)
void SetInterval(intptr_t map_number, const Interval &interval)
void Set(intptr_t map_number, intptr_t character)
BoyerMooreLookahead(intptr_t length, RegExpCompiler *compiler, Zone *Zone)
intptr_t Count(intptr_t map_number)
void SetRest(intptr_t from_map)
void EmitSkipInstructions(RegExpMacroAssembler *masm)
void Set(intptr_t character)
static constexpr intptr_t kMapSize
void SetInterval(const Interval &interval)
virtual void SetCurrentPositionFromEnd(intptr_t by)
virtual void PrintBlocks()
static bool IsCanonical(ZoneGrowableArray< CharacterRange > *ranges)
static void AddClassEscape(uint16_t type, ZoneGrowableArray< CharacterRange > *ranges)
static CharacterRange Range(int32_t from, int32_t to)
static CharacterRange Everything()
bool Contains(int32_t i) const
static CharacterRange Singleton(int32_t value)
void set_from(int32_t value)
static void Canonicalize(ZoneGrowableArray< CharacterRange > *ranges)
static void AddCaseEquivalents(ZoneGrowableArray< CharacterRange > *ranges, bool is_one_byte, Zone *zone)
static void Negate(ZoneGrowableArray< CharacterRange > *src, ZoneGrowableArray< CharacterRange > *dst)
static ZoneGrowableArray< CharacterRange > * List(Zone *zone, CharacterRange range)
void set_standard_set_type(uint16_t special_set_type)
ZoneGrowableArray< CharacterRange > * ranges()
virtual bool try_to_emit_quick_check_for_alternative(bool is_first)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
ZoneGrowableArray< GuardedAlternative > * alternatives_
virtual RegExpNode * FilterOneByte(intptr_t depth)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
intptr_t EatsAtLeastHelper(intptr_t still_to_find, intptr_t budget, RegExpNode *ignore_this_node, bool not_at_start)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t characters_filled_in, bool not_at_start)
void AddAlternative(GuardedAlternative node)
intptr_t GreedyLoopTextLengthForAlternative(const GuardedAlternative *alternative)
ZoneGrowableArray< GuardedAlternative > * alternatives()
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static const int32_t kNoKey
void set_to(int32_t value)
void AddValue(int value, Zone *zone)
OutSet * Get(int32_t value)
void AddRange(CharacterRange range, int32_t value, Zone *zone)
void ForEach(Callback *callback)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
intptr_t Frequency(intptr_t in_character)
void CountCharacter(intptr_t character)
void set_result_type(const AbstractType &value) const
void SetParameterTypeAt(intptr_t index, const AbstractType &value) const
void set_num_fixed_parameters(intptr_t value) const
void set_parameter_types(const Array &value) const
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kNonNullable, Heap::Space space=Heap::kOld)
void CreateNameArray(Heap::Space space=Heap::kOld) const
static FunctionPtr New(const FunctionType &signature, const String &name, UntaggedFunction::Kind kind, bool is_static, bool is_const, bool is_abstract, bool is_external, bool is_native, const Object &owner, TokenPosition token_pos, Heap::Space space=Heap::kOld)
void SetParameterNameAt(intptr_t index, const String &value) const
void SetRegExpData(const RegExp ®exp, intptr_t string_specialization_cid, bool sticky) const
GreedyLoopState(bool not_at_start)
Trace * counter_backtrack_trace()
RegExpNode * node() const
ZoneGrowableArray< Guard * > * guards() const
void AddGuard(Guard *guard, Zone *zone)
virtual void PrintBlocks()
virtual void SetCurrentPositionFromEnd(intptr_t by)
bool Contains(intptr_t value) const
static uint16_t TryConvertToLatin1(uint16_t c)
static LibraryPtr CoreLibrary()
ClassPtr LookupClass(const String &name) const
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
virtual void Accept(NodeVisitor *visitor)
void AddContinueAlternative(GuardedAlternative alt)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t characters_filled_in, bool not_at_start)
void AddLoopAlternative(GuardedAlternative alt)
virtual RegExpNode * FilterOneByte(intptr_t depth)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
virtual RegExpNode * FilterOneByte(intptr_t depth)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t characters_filled_in, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void VisitLoopChoice(LoopChoiceNode *that)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static Object & ZoneHandle()
OutSet * Extend(unsigned value, Zone *zone)
bool Get(unsigned value) const
const Function & function() const
Position * positions(intptr_t index)
bool Rationalize(bool one_byte)
void Advance(intptr_t by, bool one_byte)
void Merge(QuickCheckDetails *other, intptr_t from_index)
RecursionCheck(RegExpCompiler *compiler)
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
AssertionType assertion_type() const
RegExpFlags flags() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual void AppendToText(RegExpText *text)
ZoneGrowableArray< uint16_t > * data() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
static intptr_t EndRegister(intptr_t index)
static intptr_t StartRegister(intptr_t index)
uint16_t standard_type() const
RegExpCharacterClass(ZoneGrowableArray< CharacterRange > *ranges, RegExpFlags flags, CharacterClassFlags character_class_flags=DefaultFlags())
virtual void AppendToText(RegExpText *text)
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
bool contains_split_surrogate() const
ZoneGrowableArray< CharacterRange > * ranges()
intptr_t AllocateRegister()
static constexpr intptr_t kImplementationOffset
void AddWork(RegExpNode *node)
void set_read_backward(bool value)
static constexpr intptr_t kMaxRecursion
RegExpCompiler(intptr_t capture_count, bool is_one_byte)
void set_current_expansion_factor(intptr_t value)
RegExpEngine::CompilationResult Assemble(IRRegExpMacroAssembler *assembler, RegExpNode *start, intptr_t capture_count, const String &pattern)
void DecrementRecursionDepth()
FrequencyCollator * frequency_collator()
intptr_t UnicodeLookaroundPositionRegister()
static constexpr intptr_t kCodeOffset
static constexpr intptr_t kNoRegister
intptr_t UnicodeLookaroundStackRegister()
RegExpMacroAssembler * macro_assembler()
intptr_t recursion_depth()
void IncrementRecursionDepth()
intptr_t current_expansion_factor()
static constexpr intptr_t kNumberOfRegistersOffset
ZoneGrowableArray< RegExpTree * > * alternatives() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
static void DotPrint(const char *label, RegExpNode *node, bool ignore_case)
static CompilationResult CompileBytecode(RegExpCompileData *data, const RegExp ®exp, bool is_one_byte, bool sticky, Zone *zone)
static CompilationResult CompileIR(RegExpCompileData *input, const ParsedFunction *parsed_function, const ZoneGrowableArray< const ICData * > &ic_data_array, intptr_t osr_id)
static RegExpPtr CreateRegExp(Thread *thread, const String &pattern, RegExpFlags flags)
RegExpExpansionLimiter(RegExpCompiler *compiler, intptr_t factor)
static constexpr intptr_t kMaxExpansionFactor
~RegExpExpansionLimiter()
bool NeedsUnicodeCaseEquivalents()
RegExpNode * on_match_success()
Builder(bool is_positive, RegExpNode *on_success, intptr_t stack_pointer_register, intptr_t position_register, intptr_t capture_register_count=0, intptr_t capture_register_start=0)
RegExpNode * ForMatch(RegExpNode *match)
RegExpTree * body() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
void set_global_mode(GlobalMode mode)
virtual void CheckCharacterLT(uint16_t limit, BlockLabel *on_less)=0
virtual void CheckCharacterInRange(uint16_t from, uint16_t to, BlockLabel *on_in_range)=0
virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg, bool read_backward, bool unicode, BlockLabel *on_no_match)=0
virtual void CheckNotCharacter(unsigned c, BlockLabel *on_not_equal)=0
virtual void ReadStackPointerFromRegister(intptr_t reg)=0
static constexpr intptr_t kTableSizeBits
static constexpr intptr_t kTableMask
virtual void PopCurrentPosition()=0
virtual void CheckNotAtStart(intptr_t cp_offset, BlockLabel *on_not_at_start)=0
virtual void CheckPosition(intptr_t cp_offset, BlockLabel *on_outside_input)
virtual void CheckAtStart(BlockLabel *on_at_start)=0
static constexpr intptr_t kTableSize
virtual void CheckCharacterAfterAnd(unsigned c, unsigned and_with, BlockLabel *on_equal)=0
virtual void IfRegisterGE(intptr_t reg, intptr_t comparand, BlockLabel *if_ge)=0
virtual void ReadCurrentPositionFromRegister(intptr_t reg)=0
virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset)=0
virtual void CheckCharacterNotInRange(uint16_t from, uint16_t to, BlockLabel *on_not_in_range)=0
virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, BlockLabel *on_not_equal)=0
virtual void IfRegisterEqPos(intptr_t reg, BlockLabel *if_eq)=0
virtual void CheckCharacterGT(uint16_t limit, BlockLabel *on_greater)=0
virtual void CheckNotBackReference(intptr_t start_reg, bool read_backward, BlockLabel *on_no_match)=0
virtual void PushCurrentPosition()=0
virtual void AdvanceCurrentPosition(intptr_t by)=0
virtual void BindBlock(BlockLabel *label)=0
virtual void CheckCharacter(unsigned c, BlockLabel *on_equal)=0
virtual void IfRegisterLT(intptr_t reg, intptr_t comparand, BlockLabel *if_lt)=0
void set_slow_safe(bool ssc)
virtual void CheckGreedyLoop(BlockLabel *on_tos_equals_current_position)=0
virtual void GoTo(BlockLabel *to)=0
virtual void CheckBitInTable(const TypedData &table, BlockLabel *on_bit_set)=0
void CheckNotInSurrogatePair(intptr_t cp_offset, BlockLabel *on_failure)
virtual bool CheckSpecialCharacterClass(uint16_t type, BlockLabel *on_no_match)
virtual void Backtrack()=0
virtual void CheckNotCharacterAfterMinusAnd(uint16_t c, uint16_t minus, uint16_t and_with, BlockLabel *on_not_equal)=0
virtual void LoadCurrentCharacter(intptr_t cp_offset, BlockLabel *on_end_of_input, bool check_bounds=true, intptr_t characters=1)=0
virtual void PushBacktrack(BlockLabel *label)=0
virtual void WriteStackPointerToRegister(intptr_t reg)=0
virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to)=0
static constexpr intptr_t kMaxCPOffset
virtual void CheckPreemption(bool is_backtrack)
@ GLOBAL_NO_ZERO_LENGTH_CHECK
virtual void Accept(NodeVisitor *visitor)=0
virtual void Emit(RegExpCompiler *compiler, Trace *trace)=0
static constexpr intptr_t kNodeIsTooComplexForGreedyLoops
virtual RegExpNode * FilterOneByte(intptr_t depth)
LimitResult LimitVersions(RegExpCompiler *compiler, Trace *trace)
bool EmitQuickCheck(RegExpCompiler *compiler, Trace *bounds_check_trace, Trace *trace, bool preload_has_checked_bounds, BlockLabel *on_possible_success, QuickCheckDetails *details_return, bool fall_through_on_failure)
BoyerMooreLookahead * bm_info(bool not_at_start)
virtual intptr_t GreedyLoopTextLength()
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
static constexpr intptr_t kRecursionBudget
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)=0
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t characters_filled_in, bool not_at_start)=0
RegExpTree * body() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual void AppendToText(RegExpText *text)
GrowableArray< TextElement > * elements()
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
virtual intptr_t min_match() const =0
virtual Interval CaptureRegisters() const
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)=0
static constexpr intptr_t kInfinity
virtual void AppendToText(RegExpText *text)
void set_pattern(const String &pattern) const
StringPtr pattern() const
void set_function(intptr_t cid, bool sticky, const Function &value) const
static RegExpPtr New(Zone *zone, Heap::Space space=Heap::kNew)
void set_is_complex() const
void set_flags(RegExpFlags flags) const
RegExpFlags flags() const
void set_is_global() const
RegExpNode * on_success()
virtual RegExpNode * FilterOneByte(intptr_t depth)
RegExpNode * FilterSuccessor(intptr_t depth)
bool Insert(const Key &key, Locator *locator)
static const String & This()
static TextElement CharClass(RegExpCharacterClass *char_class)
TextType text_type() const
RegExpCharacterClass * char_class() const
static TextElement Atom(RegExpAtom *atom)
intptr_t cp_offset() const
RegExpAtom * atom() const
void set_cp_offset(intptr_t cp_offset)
virtual RegExpNode * FilterOneByte(intptr_t depth)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual RegExpNode * GetSuccessorOfOmnivorousTextNode(RegExpCompiler *compiler)
virtual intptr_t GreedyLoopTextLength()
static TextNode * CreateForCharacterRanges(ZoneGrowableArray< CharacterRange > *ranges, bool read_backward, RegExpNode *on_success, RegExpFlags flags)
virtual intptr_t EatsAtLeast(intptr_t still_to_find, intptr_t budget, bool not_at_start)
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
void MakeCaseIndependent(bool is_one_byte)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, intptr_t characters_filled_in, bool not_at_start)
static TextNode * CreateForSurrogatePair(CharacterRange lead, CharacterRange trail, bool read_backward, RegExpNode *on_success, RegExpFlags flags)
static Thread * Current()
static const TokenPosition kMinSource
bool Mentions(intptr_t reg)
ActionNode::ActionType action_type()
intptr_t characters_preloaded()
QuickCheckDetails * quick_check_performed()
bool GetStoredPosition(intptr_t reg, intptr_t *cp_offset)
void set_loop_label(BlockLabel *label)
void InvalidateCurrentCharacter()
void set_at_start(TriBool at_start)
void set_bound_checked_up_to(intptr_t to)
BlockLabel * loop_label()
void Flush(RegExpCompiler *compiler, RegExpNode *successor)
void set_characters_preloaded(intptr_t count)
bool mentions_reg(intptr_t reg)
void set_stop_node(RegExpNode *node)
intptr_t bound_checked_up_to()
void set_quick_check_performed(QuickCheckDetails *d)
DeferredAction * actions()
void add_action(DeferredAction *new_action)
void set_flush_budget(intptr_t to)
void AdvanceCurrentPositionInTrace(intptr_t by, RegExpCompiler *compiler)
void set_backtrack(BlockLabel *backtrack)
static TypePtr ArrayType()
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
ZoneGrowableArray< CharacterRange > * lead_surrogates()
UnicodeRangeSplitter(Zone *zone, ZoneGrowableArray< CharacterRange > *base)
ZoneGrowableArray< CharacterRange > * trail_surrogates()
ZoneGrowableArray< CharacterRange > * non_bmp() const
ZoneGrowableArray< CharacterRange > * bmp()
void Call(uint32_t from, ChoiceTable::Entry entry)
static constexpr int32_t kLeadSurrogateStart
static constexpr int32_t kMaxCodeUnit
static constexpr int32_t kTrailSurrogateStart
static void Encode(int32_t codepoint, uint16_t *dst)
static constexpr int32_t kTrailSurrogateEnd
static constexpr int32_t kLeadSurrogateEnd
static constexpr int32_t kMaxCodePoint
static constexpr int32_t kInvalidChar
static constexpr T Maximum(T x, T y)
static T Minimum(T x, T y)
VisitMarker(NodeInfo *info)
intptr_t get(int32_t c, int32_t n, int32_t *result)
#define DECLARE_VISIT(type, attrs)
EMSCRIPTEN_KEEPALIVE void empty()
FlutterSemanticsFlag flags
Dart_NativeFunction function
static float max(float r, float g, float b)
static float min(float r, float g, float b)
const GrXPFactory * Get(SkBlendMode mode)
static constexpr intptr_t kWordRangeCount
static void SplitSearchSpace(ZoneGrowableArray< uint16_t > *ranges, intptr_t start_index, intptr_t end_index, intptr_t *new_start_index, intptr_t *new_end_index, uint16_t *border)
static constexpr intptr_t kMaxLookaheadForBoyerMoore
static constexpr int32_t kLineTerminatorRanges[]
static intptr_t InsertRangeInCanonicalList(ZoneGrowableArray< CharacterRange > *list, intptr_t count, CharacterRange insert)
static bool CompareInverseRanges(ZoneGrowableArray< CharacterRange > *ranges, const int32_t *special_class, intptr_t length)
static void AddClassNegated(const int32_t *elmv, intptr_t elmc, ZoneGrowableArray< CharacterRange > *ranges)
constexpr int32_t kMinInt32
void PrintUtf16(uint16_t c)
void AddBmpCharacters(RegExpCompiler *compiler, ChoiceNode *result, RegExpNode *on_success, UnicodeRangeSplitter *splitter)
static void EmitCharClass(RegExpMacroAssembler *macro_assembler, RegExpCharacterClass *cc, bool one_byte, BlockLabel *on_failure, intptr_t cp_offset, bool check_offset, bool preloaded, Zone *zone)
static constexpr intptr_t kSurrogateRangeCount
static void EmitHat(RegExpCompiler *compiler, RegExpNode *on_success, Trace *trace)
static constexpr int32_t kSpaceRanges[]
void AddLoneLeadSurrogates(RegExpCompiler *compiler, ChoiceNode *result, RegExpNode *on_success, UnicodeRangeSplitter *splitter)
static constexpr bool kRegexpOptimization
static uint16_t ConvertNonLatin1ToLatin1(uint16_t c)
static constexpr int32_t kRangeEndMarker
static void UpdateBoundsCheck(intptr_t index, intptr_t *checked_up_to)
static bool ShortCutEmitCharacterPair(RegExpMacroAssembler *macro_assembler, bool one_byte, uint16_t c1, uint16_t c2, BlockLabel *on_failure)
ContainedInLattice AddRange(ContainedInLattice containment, const int32_t *ranges, intptr_t ranges_length, Interval new_range)
static bool RangeContainsLatin1Equivalents(CharacterRange range)
static void EmitDoubleBoundaryTest(RegExpMacroAssembler *masm, uint16_t first, uint16_t last, BlockLabel *fall_through, BlockLabel *in_range, BlockLabel *out_of_range)
void CreateSpecializedFunction(Thread *thread, Zone *zone, const RegExp ®exp, intptr_t specialization_cid, bool sticky, const Object &owner)
void AddNonBmpSurrogatePairs(RegExpCompiler *compiler, ChoiceNode *result, RegExpNode *on_success, UnicodeRangeSplitter *splitter)
RegExpNode * MatchAndNegativeLookaroundInReadDirection(RegExpCompiler *compiler, ZoneGrowableArray< CharacterRange > *match, ZoneGrowableArray< CharacterRange > *lookahead, RegExpNode *on_success, bool read_backward, RegExpFlags flags)
static constexpr int32_t kWordRanges[]
static constexpr int32_t kSurrogateRanges[]
static constexpr intptr_t kSpaceRangeCount
static bool EmitAtomLetter(Zone *zone, RegExpCompiler *compiler, uint16_t c, BlockLabel *on_failure, intptr_t cp_offset, bool check, bool preloaded)
static void EmitWordCheck(RegExpMacroAssembler *assembler, BlockLabel *word, BlockLabel *non_word, bool fall_through_on_word)
RegExpNode * OptionallyStepBackToLeadSurrogate(RegExpCompiler *compiler, RegExpNode *on_success, RegExpFlags flags)
bool EmitCharacterFunction(Zone *zone, RegExpCompiler *compiler, uint16_t c, BlockLabel *on_failure, intptr_t cp_offset, bool check, bool preloaded)
void AddUnicodeCaseEquivalents(ZoneGrowableArray< CharacterRange > *ranges)
ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b)
void AddLoneTrailSurrogates(RegExpCompiler *compiler, ChoiceNode *result, RegExpNode *on_success, UnicodeRangeSplitter *splitter)
static bool ArrayContains(ZoneGrowableArray< unsigned > *array, unsigned value)
static void CutOutRange(RegExpMacroAssembler *masm, ZoneGrowableArray< uint16_t > *ranges, intptr_t start_index, intptr_t end_index, intptr_t cut_index, BlockLabel *even_label, BlockLabel *odd_label)
RegExpNode * NegativeLookaroundAgainstReadDirectionAndMatch(RegExpCompiler *compiler, ZoneGrowableArray< CharacterRange > *lookbehind, ZoneGrowableArray< CharacterRange > *match, RegExpNode *on_success, bool read_backward, RegExpFlags flags)
static constexpr intptr_t kDigitRangeCount
static uint32_t SmearBitsRight(uint32_t v)
static void AddClass(const int32_t *elmv, intptr_t elmc, ZoneGrowableArray< CharacterRange > *ranges)
static intptr_t GetCaseIndependentLetters(uint16_t character, bool one_byte_subject, int32_t *letters)
static void GenerateBranches(RegExpMacroAssembler *masm, ZoneGrowableArray< uint16_t > *ranges, intptr_t start_index, intptr_t end_index, uint16_t min_char, uint16_t max_char, BlockLabel *fall_through, BlockLabel *even_label, BlockLabel *odd_label)
static bool EmitAtomNonLetter(Zone *zone, RegExpCompiler *compiler, uint16_t c, BlockLabel *on_failure, intptr_t cp_offset, bool check, bool preloaded)
static int8_t data[kExtLength]
static constexpr intptr_t kLineTerminatorRangeCount
RegExpNode * UnanchoredAdvance(RegExpCompiler *compiler, RegExpNode *on_success)
static constexpr int32_t kDigitRanges[]
static void MoveRanges(ZoneGrowableArray< CharacterRange > *list, intptr_t from, intptr_t to, intptr_t count)
static void EmitUseLookupTable(RegExpMacroAssembler *masm, ZoneGrowableArray< uint16_t > *ranges, intptr_t start_index, intptr_t end_index, uint16_t min_char, BlockLabel *fall_through, BlockLabel *even_label, BlockLabel *odd_label)
static void EmitBoundaryTest(RegExpMacroAssembler *masm, uint16_t border, BlockLabel *fall_through, BlockLabel *above_or_equal, BlockLabel *below)
static RegExpEngine::CompilationResult IrregexpRegExpTooBig()
static bool RangesContainLatin1Equivalents(ZoneGrowableArray< CharacterRange > *ranges)
COMPILE_ASSERT(kUnreachableReference==WeakTable::kNoValue)
static bool EmitSimpleCharacter(Zone *zone, RegExpCompiler *compiler, uint16_t c, BlockLabel *on_failure, intptr_t cp_offset, bool check, bool preloaded)
static bool DeterminedAlready(QuickCheckDetails *quick_check, intptr_t offset)
static bool CompareRanges(ZoneGrowableArray< CharacterRange > *ranges, const int32_t *special_class, intptr_t length)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
#define FOR_EACH_NODE_TYPE(VISIT)
QuickCheckDetails quick_check_details
BlockLabel possible_success
static constexpr intptr_t kEatsAtLeastNotYetInitialized
intptr_t preload_characters_
bool determines_perfectly
static constexpr intptr_t kMaxWidth
#define ARRAY_SIZE(array)
#define DEFINE_ACCEPT(Type)