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:
762 result->data_.u_store_register.value = val;
769 new (on_success->
zone())
ActionNode(INCREMENT_REGISTER, on_success);
780 result->data_.u_position_register.is_capture = is_capture;
788 result->data_.u_clear_captures.range_to = range.
to();
793 intptr_t position_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);
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);
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++) {
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++) {
1566 RegExpNode* node = (*alternatives_)[i].node();
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++) {
2154 RegExpNode* node = (*alternatives_)[i].node();
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++)
2835 for (intptr_t i = 0; i <
length; 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_ =
3117 current_trace->at_start() == Trace::FALSE_VALUE);
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) {
3620 OS::PrintErr(
"{%s}",
name);
3622 void PrintPositive(
const char*
name, intptr_t value) {
3623 if (value < 0)
return;
3625 OS::PrintErr(
"{%s|%" Pd "}",
name, value);
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) {
4208 for (intptr_t i = 0; i <
length; i++) {
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()
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) {
4606 ASSERT(elmv[i] < elmv[i + 1]);
4616 ASSERT(elmv[0] != 0x0000);
4618 uint16_t last = 0x0000;
4619 for (intptr_t i = 0; i < elmc; i += 2) {
4620 ASSERT(last <= elmv[i] - 1);
4621 ASSERT(elmv[i] < elmv[i + 1]);
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);
4720 for (intptr_t i = 0; i <
length; i++) {
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);
4758 for (intptr_t i = 0; i <
length; i++) {
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++) {
4948 if (Get(
value))
return this;
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);
4970 bool remaining_contains_value =
ArrayContains(remaining_, value);
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()) {
5025 bool inserted = tree()->
Insert(
right.from(), &loc);
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);
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 bool match(const char *needle, const char *haystack)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static constexpr uint64_t kBits
static constexpr uint64_t kMask
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)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static SkScalar center(float pos0, float pos1)
#define COMPILE_ASSERT(expr)
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
struct dart::ActionNode::@201::@207 u_clear_captures
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)
intptr_t stack_pointer_register
struct dart::ActionNode::@201::@206 u_empty_match_check
static ActionNode * IncrementRegister(intptr_t reg, RegExpNode *on_success)
static ActionNode * ClearCaptures(Interval range, RegExpNode *on_success)
struct dart::ActionNode::@201::@205 u_submatch
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
struct dart::ActionNode::@201::@203 u_increment_register
virtual void FillInBMInfo(intptr_t offset, intptr_t budget, BoyerMooreLookahead *bm, bool not_at_start)
struct dart::ActionNode::@201::@204 u_position_register
struct dart::ActionNode::@201::@202 u_store_register
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::kLegacy, 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)
intptr_t string_specialization_cid() const
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
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)
static constexpr int kSize
#define DECLARE_VISIT(type, attrs)
EMSCRIPTEN_KEEPALIVE void empty()
FlutterSemanticsFlag flags
static const uint8_t buffer[]
Dart_NativeFunction function
static float max(float r, float g, float b)
static float min(float r, float g, float b)
#define DEFINE_ACCEPT(ShortName, Attrs)
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)
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)
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)