24 #ifndef V8_INTERPRETED_REGEXP
25 #if V8_TARGET_ARCH_IA32
27 #elif V8_TARGET_ARCH_X64
29 #elif V8_TARGET_ARCH_ARM64
31 #elif V8_TARGET_ARCH_ARM
33 #elif V8_TARGET_ARCH_MIPS
35 #elif V8_TARGET_ARCH_MIPS64
37 #elif V8_TARGET_ARCH_X87
40 #error Unsupported target architecture.
56 return Execution::New(constructor,
arraysize(argv), argv);
62 for (
int i = 0;
i < str->length();
i++) {
63 switch (str->Get(
i)) {
87 const char* message) {
88 Isolate* isolate = re->GetIsolate();
89 Factory* factory = isolate->
factory();
91 elements->set(0, *pattern);
92 elements->set(1, *error_text);
103 DCHECK((ranges_length & 1) == 1);
108 for (
int i = 0;
i < ranges_length; inside = !inside, last = ranges[
i],
i++) {
111 if (ranges[
i] <= new_range.
from())
continue;
114 if (last <= new_range.
from() && new_range.
to() < ranges[
i]) {
135 const int kMod = 128;
136 bool character_found[kMod];
138 memset(&character_found[0], 0,
sizeof(character_found));
139 for (
int i = 0;
i < length;
i++) {
140 int ch = (pattern->Get(
i) & (kMod - 1));
141 if (!character_found[ch]) {
142 character_found[ch] =
true;
146 if (different * 3 > length)
return false;
159 Isolate* isolate = re->GetIsolate();
166 bool in_cache = maybe_cached.ToHandle(&cached);
167 LOG(isolate, RegExpCompileEvent(re, in_cache));
171 re->set_data(*cached);
175 PostponeInterruptsScope postpone(isolate);
178 if (!RegExpParser::ParseRegExp(&reader,
flags.is_multiline(),
179 &parse_result, &zone)) {
187 bool has_been_compiled =
false;
189 if (parse_result.
simple &&
190 !
flags.is_ignore_case() &&
191 !
flags.is_sticky() &&
195 has_been_compiled =
true;
196 }
else if (parse_result.
tree->IsAtom() &&
197 !
flags.is_ignore_case() &&
198 !
flags.is_sticky() &&
200 RegExpAtom* atom = parse_result.
tree->AsAtom();
204 isolate, atom_string,
205 isolate->
factory()->NewStringFromTwoByte(atom_pattern),
209 has_been_compiled =
true;
212 if (!has_been_compiled) {
215 DCHECK(re->data()->IsFixedArray());
229 switch (regexp->TypeTag()) {
231 return AtomExec(regexp, subject, index, last_match_info);
233 return IrregexpExec(regexp, subject, index, last_match_info);
249 re->GetIsolate()->factory()->SetRegExpAtomData(re,
275 Isolate* isolate = regexp->GetIsolate();
278 DCHECK(index <= subject->length());
284 int needle_len = needle->
length();
288 if (index + needle_len > subject->length()) {
292 for (
int i = 0;
i < output_size;
i += 2) {
314 output[
i+1] = index + needle_len;
318 return output_size / 2;
326 Isolate* isolate = re->GetIsolate();
330 int32_t* output_registers = isolate->jsregexp_static_offsets_vector();
337 SealHandleScope shs(isolate);
338 FixedArray* array = FixedArray::cast(last_match_info->elements());
340 return last_match_info;
356 #ifdef V8_INTERPRETED_REGEXP
357 if (compiled_code->IsByteArray())
return true;
359 if (compiled_code->IsCode())
return true;
364 if (saved_code->IsCode()) {
367 DCHECK(compiled_code->IsSmi());
377 Factory* factory = isolate->
factory();
379 elements->set(0, re->Pattern());
380 elements->set(1, *error_message);
384 factory->NewSyntaxError(
"malformed_regexp", array);
385 if (maybe_error.ToHandle(&error)) isolate->
Throw(*error);
393 Isolate* isolate = re->GetIsolate();
395 PostponeInterruptsScope postpone(isolate);
403 int entry_value = Smi::cast(entry)->value();
406 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0));
413 DCHECK(error_string->IsString());
425 if (!RegExpParser::ParseRegExp(&reader,
flags.is_multiline(),
433 "malformed_regexp"));
437 &compile_data,
flags.is_ignore_case(),
flags.is_global(),
438 flags.is_multiline(),
flags.is_sticky(), pattern, sample_subject,
495 re->GetIsolate()->factory()->SetRegExpIrregexpData(re,
508 bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
511 #ifdef V8_INTERPRETED_REGEXP
531 Isolate* isolate = regexp->GetIsolate();
536 DCHECK(index <= subject->length());
537 DCHECK(subject->IsFlat());
539 bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
541 #ifndef V8_INTERPRETED_REGEXP
575 is_one_byte = subject->IsOneByteRepresentationUnderneath();
584 int number_of_capture_registers =
586 int32_t* raw_output = &output[number_of_capture_registers];
590 for (
int i = number_of_capture_registers - 1;
i >= 0;
i--) {
603 MemCopy(output, raw_output, number_of_capture_registers *
sizeof(
int32_t));
618 Isolate* isolate = regexp->GetIsolate();
622 #if defined(V8_INTERPRETED_REGEXP) && defined(DEBUG)
623 if (FLAG_trace_regexp_bytecodes) {
624 String* pattern = regexp->Pattern();
626 PrintF(
"\n\nSubject string: '%s'\n\n", subject->ToCString().get());
630 if (required_registers < 0) {
638 output_registers = NewArray<int32_t>(required_registers);
641 if (output_registers ==
NULL) {
642 output_registers = isolate->jsregexp_static_offsets_vector();
646 regexp, subject, previous_index, output_registers, required_registers);
651 last_match_info, subject, capture_count, output_registers);
658 return isolate->
factory()->null_value();
666 DCHECK(last_match_info->HasFastObjectElements());
667 int capture_register_count = (capture_count + 1) * 2;
671 FixedArray* array = FixedArray::cast(last_match_info->elements());
673 for (
int i = 0;
i < capture_register_count;
i += 2) {
681 return last_match_info;
689 : register_array_(
NULL),
690 register_array_size_(0),
693 #ifdef V8_INTERPRETED_REGEXP
694 bool interpreted =
true;
696 bool interpreted =
false;
700 static const int kAtomRegistersPerMatch = 2;
712 if (is_global && !interpreted) {
897 void RegExpAtom::AppendToText(RegExpText* text,
Zone* zone) {
898 text->AddElement(TextElement::Atom(
this), zone);
902 void RegExpCharacterClass::AppendToText(RegExpText* text, Zone* zone) {
903 text->AddElement(TextElement::CharClass(
this), zone);
907 void RegExpText::AppendToText(RegExpText* text, Zone* zone) {
908 for (
int i = 0;
i < elements()->length();
i++)
909 text->AddElement(elements()->at(
i), zone);
913 TextElement TextElement::Atom(RegExpAtom* atom) {
914 return TextElement(ATOM, atom);
918 TextElement TextElement::CharClass(RegExpCharacterClass* char_class) {
919 return TextElement(CHAR_CLASS, char_class);
923 int TextElement::length()
const {
924 switch (text_type()) {
926 return atom()->length();
937 if (table_ ==
NULL) {
956 frequencies_[index].Increment();
964 if (total_samples_ < 1)
return 1;
966 (frequencies_[in_character].counter() * 128) / total_samples_;
967 return freq_in_per128;
975 : counter_(0), character_(character) { }
995 RegExpCompiler(
int capture_count,
bool ignore_case,
bool is_one_byte,
1000 reg_exp_too_big_ =
true;
1001 return next_register_;
1003 return next_register_++;
1013 static const int kImplementationOffset = 0;
1014 static const int kNumberOfRegistersOffset = 0;
1015 static const int kCodeOffset = 1;
1020 static const int kMaxRecursion = 100;
1033 current_expansion_factor_ = value;
1074 bool one_byte,
Zone* zone)
1075 : next_register_(2 * (capture_count + 1)),
1077 recursion_depth_(0),
1078 ignore_case_(ignore_case),
1079 one_byte_(one_byte),
1080 reg_exp_too_big_(
false),
1081 current_expansion_factor_(1),
1082 frequency_collator_(),
1094 Heap* heap = pattern->GetHeap();
1096 bool use_slow_safe_regexp_compiler =
false;
1101 use_slow_safe_regexp_compiler =
true;
1107 if (FLAG_trace_regexp_assembler)
1118 start->
Emit(
this, &new_trace);
1121 while (!work_list.is_empty()) {
1122 work_list.RemoveLast()->Emit(
this, &new_trace);
1130 if (FLAG_print_code) {
1135 if (FLAG_trace_regexp_assembler) {
1148 return reg() == that;
1156 action = action->next()) {
1157 if (action->Mentions(reg))
1168 action = action->next()) {
1169 if (action->Mentions(reg)) {
1187 action = action->next()) {
1190 for (
int i = range.
from();
i <= range.
to();
i++)
1191 affected_registers->
Set(
i, zone);
1192 if (range.
to() > max_register) max_register = range.
to();
1194 affected_registers->
Set(action->reg(), zone);
1195 if (action->reg() > max_register) max_register = action->reg();
1198 return max_register;
1204 const OutSet& registers_to_pop,
1205 const OutSet& registers_to_clear) {
1206 for (
int reg = max_register; reg >= 0; reg--) {
1207 if (registers_to_pop.
Get(reg)) {
1209 }
else if (registers_to_clear.
Get(reg)) {
1211 while (reg > 0 && registers_to_clear.
Get(reg - 1)) {
1222 const OutSet& affected_registers,
1223 OutSet* registers_to_pop,
1224 OutSet* registers_to_clear,
1232 for (
int reg = 0; reg <= max_register; reg++) {
1233 if (!affected_registers.
Get(reg)) {
1240 enum DeferredActionUndoType { IGNORE, RESTORE, CLEAR };
1241 DeferredActionUndoType undo_action = IGNORE;
1244 bool absolute =
false;
1246 int store_position = -1;
1251 action = action->next()) {
1252 if (action->Mentions(reg)) {
1253 switch (action->action_type()) {
1258 value += psr->
value();
1266 undo_action = RESTORE;
1277 undo_action = RESTORE;
1282 if (!clear && store_position == -1) {
1283 store_position =
pc->cp_offset();
1294 undo_action = IGNORE;
1296 undo_action =
pc->is_capture() ? CLEAR : RESTORE;
1306 if (store_position == -1) {
1309 undo_action = RESTORE;
1321 if (undo_action == RESTORE) {
1325 if (pushes == push_limit) {
1331 registers_to_pop->
Set(reg, zone);
1332 }
else if (undo_action == CLEAR) {
1333 registers_to_clear->
Set(reg, zone);
1337 if (store_position != -1) {
1341 }
else if (absolute) {
1343 }
else if (value != 0) {
1365 successor->
Emit(compiler, &new_state);
1370 OutSet affected_registers;
1382 OutSet registers_to_clear;
1387 ®isters_to_clear,
1397 successor->
Emit(compiler, &new_state);
1400 assembler->
Bind(&undo);
1404 registers_to_clear);
1419 if (!label()->is_bound()) {
1422 assembler->
Bind(label());
1429 if (clear_capture_count_ > 0) {
1432 int clear_capture_end = clear_capture_start_ + clear_capture_count_ - 1;
1433 assembler->
ClearRegisters(clear_capture_start_, clear_capture_end);
1443 trace->
Flush(compiler,
this);
1447 if (!label()->is_bound()) {
1448 assembler->
Bind(label());
1457 case NEGATIVE_SUBMATCH_SUCCESS:
1466 if (guards_ ==
NULL)
1468 guards_->
Add(guard, zone);
1485 new(on_success->
zone())
ActionNode(INCREMENT_REGISTER, on_success);
1525 int clear_register_count,
1526 int clear_register_from,
1529 new(on_success->
zone())
ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success);
1539 int repetition_register,
1540 int repetition_limit,
1543 new(on_success->
zone())
ActionNode(EMPTY_MATCH_CHECK, on_success);
1551 #define DEFINE_ACCEPT(Type) \
1552 void Type##Node::Accept(NodeVisitor* visitor) { \
1553 visitor->Visit##Type(this); \
1556 #undef DEFINE_ACCEPT
1571 switch (guard->
op()) {
1591 bool one_byte_subject,
1598 letters[0] = character;
1621 bool bound_checked =
false;
1627 bound_checked =
true;
1630 return bound_checked;
1644 bool one_byte = compiler->
one_byte();
1653 bool checked =
false;
1672 Label* on_failure) {
1679 uc16 exor = c1 ^ c2;
1681 if (((exor - 1) & exor) == 0) {
1685 uc16 mask = char_mask ^ exor;
1690 uc16 diff = c2 - c1;
1691 if (((diff - 1) & diff) == 0 && c1 >= diff) {
1696 uc16 mask = char_mask ^ diff;
1725 bool one_byte = compiler->
one_byte();
1728 if (length <= 1)
return false;
1739 chars[1], on_failure)) {
1743 macro_assembler->
Bind(&ok);
1754 macro_assembler->
Bind(&ok);
1766 Label* fall_through,
1767 Label* above_or_equal,
1769 if (
below != fall_through) {
1771 if (above_or_equal != fall_through) masm->
GoTo(above_or_equal);
1781 Label* fall_through,
1783 Label* out_of_range) {
1784 if (in_range == fall_through) {
1785 if (first == last) {
1791 if (first == last) {
1796 if (out_of_range != fall_through) masm->
GoTo(out_of_range);
1809 Label* fall_through,
1815 int base = (min_char & ~kMask);
1819 for (
int i = start_index;
i <= end_index;
i++) {
1822 DCHECK(start_index == 0 || (ranges->
at(start_index - 1) & ~kMask) <= base);
1826 Label* on_bit_clear;
1828 if (even_label == fall_through) {
1829 on_bit_set = odd_label;
1830 on_bit_clear = even_label;
1833 on_bit_set = even_label;
1834 on_bit_clear = odd_label;
1837 for (
int i = 0;
i < (ranges->
at(start_index) & kMask) &&
i < kSize;
i++) {
1842 for (
int i = start_index;
i < end_index;
i++) {
1843 for (j = (ranges->
at(
i) & kMask); j < (ranges->
at(
i + 1) & kMask); j++) {
1848 for (
int i = j;
i < kSize;
i++) {
1854 for (
int i = 0;
i < kSize;
i++) {
1855 ba->set(
i, templ[
i]);
1858 if (on_bit_clear != fall_through) masm->
GoTo(on_bit_clear);
1869 bool odd = (((cut_index - start_index) & 1) == 1);
1870 Label* in_range_label = odd ? odd_label : even_label;
1873 ranges->
at(cut_index),
1874 ranges->
at(cut_index + 1) - 1,
1878 DCHECK(!dummy.is_linked());
1882 for (
int j = cut_index; j > start_index; j--) {
1883 ranges->
at(j) = ranges->
at(j - 1);
1885 for (
int j = cut_index + 1; j < end_index; j++) {
1886 ranges->
at(j) = ranges->
at(j + 1);
1896 int* new_start_index,
1902 int first = ranges->
at(start_index);
1903 int last = ranges->
at(end_index) - 1;
1905 *new_start_index = start_index;
1906 *border = (ranges->
at(start_index) & ~kMask) + kSize;
1907 while (*new_start_index < end_index) {
1908 if (ranges->
at(*new_start_index) > *border)
break;
1909 (*new_start_index)++;
1922 int binary_chop_index = (end_index + start_index) / 2;
1928 end_index - start_index > (*new_start_index - start_index) * 2 &&
1929 last - first > kSize * 2 && binary_chop_index > *new_start_index &&
1930 ranges->
at(binary_chop_index) >= first + 2 * kSize) {
1931 int scan_forward_for_section_border = binary_chop_index;;
1932 int new_border = (ranges->
at(binary_chop_index) | kMask) + 1;
1934 while (scan_forward_for_section_border < end_index) {
1935 if (ranges->
at(scan_forward_for_section_border) > new_border) {
1936 *new_start_index = scan_forward_for_section_border;
1937 *border = new_border;
1940 scan_forward_for_section_border++;
1944 DCHECK(*new_start_index > start_index);
1945 *new_end_index = *new_start_index - 1;
1946 if (ranges->
at(*new_end_index) == *border) {
1949 if (*border >= ranges->
at(end_index)) {
1950 *border = ranges->
at(end_index);
1951 *new_start_index = end_index;
1952 *new_end_index = end_index - 1;
1969 Label* fall_through,
1972 int first = ranges->
at(start_index);
1973 int last = ranges->
at(end_index) - 1;
1979 if (start_index == end_index) {
1986 if (start_index + 1 == end_index) {
1988 masm, first, last, fall_through, even_label, odd_label);
1994 if (end_index - start_index <= 6) {
1997 static int kNoCutIndex = -1;
1998 int cut = kNoCutIndex;
1999 for (
int i = start_index;
i < end_index;
i++) {
2000 if (ranges->
at(
i) == ranges->
at(
i + 1) - 1) {
2005 if (cut == kNoCutIndex) cut = start_index;
2007 masm, ranges, start_index, end_index, cut, even_label, odd_label);
2025 if ((max_char >> kBits) == (min_char >> kBits)) {
2037 if ((min_char >> kBits) != (first >> kBits)) {
2051 int new_start_index = 0;
2052 int new_end_index = 0;
2063 Label*
above = &handle_rest;
2064 if (border == last + 1) {
2067 above = (end_index & 1) != (start_index & 1) ? odd_label : even_label;
2068 DCHECK(new_end_index == end_index - 1);
2073 DCHECK_LT(start_index, new_start_index);
2075 DCHECK(new_end_index + 1 == new_start_index ||
2076 (new_end_index + 2 == new_start_index &&
2077 border == ranges->
at(new_end_index + 1)));
2081 DCHECK(border < ranges->at(new_start_index) ||
2082 (border == ranges->
at(new_start_index) &&
2083 new_start_index == end_index &&
2084 new_end_index == end_index - 1 &&
2085 border == last + 1));
2086 DCHECK(new_start_index == 0 || border >= ranges->
at(new_start_index - 1));
2099 if (handle_rest.is_linked()) {
2100 masm->
Bind(&handle_rest);
2101 bool flip = (new_start_index & 1) != (start_index & 1);
2109 flip ? odd_label : even_label,
2110 flip ? even_label : odd_label);
2116 RegExpCharacterClass*
cc,
bool one_byte,
2117 Label* on_failure,
int cp_offset,
bool check_offset,
2118 bool preloaded,
Zone* zone) {
2131 int range_count = ranges->length();
2133 int last_valid_range = range_count - 1;
2134 while (last_valid_range >= 0) {
2136 if (range.
from() <= max_char) {
2142 if (last_valid_range < 0) {
2143 if (!
cc->is_negated()) {
2144 macro_assembler->
GoTo(on_failure);
2152 if (last_valid_range == 0 &&
2153 ranges->
at(0).IsEverything(max_char)) {
2154 if (
cc->is_negated()) {
2155 macro_assembler->
GoTo(on_failure);
2164 if (last_valid_range == 0 &&
2165 !
cc->is_negated() &&
2166 ranges->
at(0).IsEverything(max_char)) {
2178 if (
cc->is_standard(zone) &&
2194 bool zeroth_entry_is_failure = !
cc->is_negated();
2196 for (
int i = 0;
i <= last_valid_range;
i++) {
2198 if (range.
from() == 0) {
2200 zeroth_entry_is_failure = !zeroth_entry_is_failure;
2202 range_boundaries->
Add(range.
from(), zone);
2204 range_boundaries->
Add(range.
to() + 1, zone);
2206 int end_index = range_boundaries->length() - 1;
2207 if (range_boundaries->
at(end_index) > max_char) {
2219 zeroth_entry_is_failure ? &fall_through : on_failure,
2220 zeroth_entry_is_failure ? on_failure : &fall_through);
2221 macro_assembler->
Bind(&fall_through);
2238 if (label_.is_bound()) {
2241 macro_assembler->
GoTo(&label_);
2248 macro_assembler->
GoTo(&label_);
2252 macro_assembler->
Bind(&label_);
2259 if (FLAG_regexp_optimization &&
2260 trace_count_ < kMaxCopiesCodeGenerated &&
2268 trace->
Flush(compiler,
this);
2275 bool not_at_start) {
2276 if (budget <= 0)
return 0;
2277 if (action_type_ == POSITIVE_SUBMATCH_SUCCESS)
return 0;
2278 return on_success()->EatsAtLeast(still_to_find,
2287 bool not_at_start) {
2288 if (action_type_ == BEGIN_SUBMATCH) {
2290 }
else if (action_type_ != POSITIVE_SUBMATCH_SUCCESS) {
2291 on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
2293 SaveBMInfo(bm, not_at_start, offset);
2299 bool not_at_start) {
2300 if (budget <= 0)
return 0;
2306 if (assertion_type() == AT_START && not_at_start)
return still_to_find;
2307 return on_success()->EatsAtLeast(still_to_find,
2316 bool not_at_start) {
2318 if (assertion_type() == AT_START && not_at_start)
return;
2319 on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
2320 SaveBMInfo(bm, not_at_start, offset);
2326 bool not_at_start) {
2327 if (budget <= 0)
return 0;
2328 return on_success()->EatsAtLeast(still_to_find,
2336 bool not_at_start) {
2337 int answer = Length();
2338 if (answer >= still_to_find)
return answer;
2339 if (budget <= 0)
return answer;
2341 return answer + on_success()->EatsAtLeast(still_to_find - answer,
2349 bool not_at_start) {
2350 if (budget <= 0)
return 0;
2353 RegExpNode* node = alternatives_->at(1).node();
2354 return node->
EatsAtLeast(still_to_find, budget - 1, not_at_start);
2362 bool not_at_start) {
2365 RegExpNode* node = alternatives_->at(1).node();
2373 bool not_at_start) {
2374 if (budget <= 0)
return 0;
2376 int choice_count = alternatives_->length();
2377 budget = (budget - 1) / choice_count;
2378 for (
int i = 0;
i < choice_count;
i++) {
2380 if (node == ignore_this_node)
continue;
2381 int node_eats_at_least =
2382 node->
EatsAtLeast(still_to_find, budget, not_at_start);
2383 if (node_eats_at_least <
min)
min = node_eats_at_least;
2384 if (
min == 0)
return 0;
2392 bool not_at_start) {
2393 return EatsAtLeastHelper(still_to_find,
2402 bool not_at_start) {
2403 return EatsAtLeastHelper(still_to_find,
2422 bool found_useful_op =
false;
2432 for (
int i = 0;
i < characters_;
i++) {
2435 found_useful_op =
true;
2437 mask_ |= (pos->
mask & char_mask) << char_shift;
2438 value_ |= (pos->
value & char_mask) << char_shift;
2439 char_shift += asc ? 8 : 16;
2441 return found_useful_op;
2446 Trace* bounds_check_trace,
2448 bool preload_has_checked_bounds,
2449 Label* on_possible_success,
2451 bool fall_through_on_failure) {
2452 if (details->
characters() == 0)
return false;
2453 GetQuickCheckDetails(
2472 !preload_has_checked_bounds,
2477 bool need_mask =
true;
2488 if ((mask & char_mask) == char_mask) need_mask =
false;
2494 if ((mask & 0xffff) == 0xffff) need_mask =
false;
2496 if ((mask & 0xffff) == 0xffff) need_mask =
false;
2498 if (mask == 0xffffffff) need_mask =
false;
2502 if (fall_through_on_failure) {
2529 int characters_filled_in,
2530 bool not_at_start) {
2532 DCHECK(characters_filled_in < details->characters());
2540 for (
int k = 0; k < elms_->length(); k++) {
2541 TextElement elm = elms_->at(k);
2542 if (elm.text_type() == TextElement::ATOM) {
2544 for (
int i = 0;
i < characters &&
i < quarks.
length();
i++) {
2546 details->
positions(characters_filled_in);
2548 if (c > char_mask) {
2568 pos->
mask = char_mask;
2574 for (
int j = 1; j < length; j++) {
2575 uint32_t differing_bits = ((chars[j] & common_bits) ^ bits);
2576 common_bits ^= differing_bits;
2577 bits &= common_bits;
2583 uint32_t one_zero = (common_bits | ~char_mask);
2584 if (length == 2 && ((~one_zero) & ((~one_zero) - 1)) == 0) {
2587 pos->
mask = common_bits;
2594 pos->
mask = char_mask;
2598 characters_filled_in++;
2599 DCHECK(characters_filled_in <= details->characters());
2600 if (characters_filled_in == details->
characters()) {
2606 details->
positions(characters_filled_in);
2607 RegExpCharacterClass* tree = elm.char_class();
2609 if (tree->is_negated()) {
2617 int first_range = 0;
2618 while (ranges->
at(first_range).from() > char_mask) {
2620 if (first_range == ranges->length()) {
2629 if (
to > char_mask) {
2635 if ((differing_bits & (differing_bits + 1)) == 0 &&
2636 from + differing_bits ==
to) {
2640 uint32_t bits = (from & common_bits);
2641 for (
int i = first_range + 1;
i < ranges->length();
i++) {
2645 if (from > char_mask)
continue;
2646 if (
to > char_mask)
to = char_mask;
2655 common_bits &= new_common_bits;
2656 bits &= new_common_bits;
2657 uint32_t differing_bits = (from & common_bits) ^ bits;
2658 common_bits ^= differing_bits;
2659 bits &= common_bits;
2661 pos->
mask = common_bits;
2664 characters_filled_in++;
2665 DCHECK(characters_filled_in <= details->characters());
2666 if (characters_filled_in == details->
characters()) {
2673 on_success()-> GetQuickCheckDetails(details,
2675 characters_filled_in,
2682 for (
int i = 0;
i < characters_;
i++) {
2683 positions_[
i].mask = 0;
2684 positions_[
i].value = 0;
2685 positions_[
i].determines_perfectly =
false;
2693 if (by >= characters_) {
2697 for (
int i = 0;
i < characters_ - by;
i++) {
2698 positions_[
i] = positions_[by +
i];
2700 for (
int i = characters_ - by;
i < characters_;
i++) {
2701 positions_[
i].mask = 0;
2702 positions_[
i].value = 0;
2703 positions_[
i].determines_perfectly =
false;
2717 if (cannot_match_) {
2721 for (
int i = from_index;
i < characters_;
i++) {
2724 if (pos->
mask != other_pos->
mask ||
2735 pos->
mask &= ~differing_bits;
2748 info_->visited =
false;
2756 if (info()->replacement_calculated)
return replacement();
2757 if (depth < 0)
return this;
2758 DCHECK(!info()->visited);
2760 return FilterSuccessor(depth - 1, ignore_case);
2766 if (next ==
NULL)
return set_replacement(
NULL);
2768 return set_replacement(
this);
2781 for (
int i = 0;
i < ranges->length();
i++) {
2790 if (info()->replacement_calculated)
return replacement();
2791 if (depth < 0)
return this;
2792 DCHECK(!info()->visited);
2794 int element_count = elms_->length();
2795 for (
int i = 0;
i < element_count;
i++) {
2796 TextElement elm = elms_->at(
i);
2797 if (elm.text_type() == TextElement::ATOM) {
2799 for (
int j = 0; j < quarks.
length(); j++) {
2802 if (!ignore_case)
return set_replacement(
NULL);
2807 if (converted == 0)
return set_replacement(
NULL);
2810 copy[j] = converted;
2813 DCHECK(elm.text_type() == TextElement::CHAR_CLASS);
2814 RegExpCharacterClass*
cc = elm.char_class();
2820 int range_count = ranges->length();
2821 if (
cc->is_negated()) {
2822 if (range_count != 0 &&
2823 ranges->
at(0).from() == 0 &&
2827 return set_replacement(
NULL);
2830 if (range_count == 0 ||
2834 return set_replacement(
NULL);
2839 return FilterSuccessor(depth - 1, ignore_case);
2844 if (info()->replacement_calculated)
return replacement();
2845 if (depth < 0)
return this;
2846 if (info()->visited)
return this;
2854 if (continue_replacement ==
NULL)
return set_replacement(
NULL);
2862 if (info()->replacement_calculated)
return replacement();
2863 if (depth < 0)
return this;
2864 if (info()->visited)
return this;
2866 int choice_count = alternatives_->length();
2868 for (
int i = 0;
i < choice_count;
i++) {
2871 set_replacement(
this);
2878 for (
int i = 0;
i < choice_count;
i++) {
2882 DCHECK(replacement !=
this);
2883 if (replacement !=
NULL) {
2884 alternatives_->at(
i).set_node(replacement);
2886 survivor = replacement;
2889 if (surviving < 2)
return set_replacement(survivor);
2891 set_replacement(
this);
2892 if (surviving == choice_count) {
2899 for (
int i = 0;
i < choice_count;
i++) {
2901 alternatives_->at(
i).node()->
FilterOneByte(depth - 1, ignore_case);
2902 if (replacement !=
NULL) {
2903 alternatives_->at(
i).set_node(replacement);
2904 new_alternatives->
Add(alternatives_->at(
i), zone());
2907 alternatives_ = new_alternatives;
2914 if (info()->replacement_calculated)
return replacement();
2915 if (depth < 0)
return this;
2916 if (info()->visited)
return this;
2920 RegExpNode* node = alternatives_->at(1).node();
2922 if (replacement ==
NULL)
return set_replacement(
NULL);
2923 alternatives_->at(1).set_node(replacement);
2925 RegExpNode* neg_node = alternatives_->at(0).node();
2929 if (neg_replacement ==
NULL)
return set_replacement(replacement);
2930 alternatives_->at(0).set_node(neg_replacement);
2931 return set_replacement(
this);
2937 int characters_filled_in,
2938 bool not_at_start) {
2939 if (body_can_be_zero_length_ || info()->visited)
return;
2943 characters_filled_in,
2951 bool not_at_start) {
2952 if (body_can_be_zero_length_ || budget <= 0) {
2954 SaveBMInfo(bm, not_at_start, offset);
2958 SaveBMInfo(bm, not_at_start, offset);
2964 int characters_filled_in,
2965 bool not_at_start) {
2966 not_at_start = (not_at_start || not_at_start_);
2967 int choice_count = alternatives_->length();
2968 DCHECK(choice_count > 0);
2969 alternatives_->at(0).node()->GetQuickCheckDetails(details,
2971 characters_filled_in,
2973 for (
int i = 1;
i < choice_count;
i++) {
2977 characters_filled_in,
2980 details->
Merge(&new_details, characters_filled_in);
2989 bool fall_through_on_word) {
2991 fall_through_on_word ?
'w' :
'W',
2992 fall_through_on_word ? non_word : word)) {
3002 if (fall_through_on_word) {
3018 Trace new_trace(*trace);
3041 assembler->
Bind(&ok);
3042 on_success->
Emit(compiler, &new_trace);
3052 if (lookahead ==
NULL) {
3057 if (eats_at_least >= 1) {
3060 FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
3073 Label before_non_word;
3079 EmitWordCheck(assembler, &before_word, &before_non_word,
false);
3081 assembler->
Bind(&before_non_word);
3083 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
3084 assembler->
GoTo(&ok);
3086 assembler->
Bind(&before_word);
3087 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
3088 assembler->
Bind(&ok);
3090 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
3093 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
3103 Trace new_trace(*trace);
3106 Label fall_through, dummy;
3108 Label* non_word = backtrack_if_previous == kIsNonWord ?
3111 Label* word = backtrack_if_previous == kIsNonWord ?
3123 EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord);
3125 assembler->
Bind(&fall_through);
3126 on_success()->Emit(compiler, &new_trace);
3133 bool not_at_start) {
3134 if (assertion_type_ == AT_START && not_at_start) {
3138 return on_success()->GetQuickCheckDetails(details,
3147 switch (assertion_type_) {
3152 assembler->
Bind(&ok);
3162 Trace at_start_trace = *trace;
3164 on_success()->Emit(compiler, &at_start_trace);
3170 EmitHat(compiler, on_success(), trace);
3173 case AT_NON_BOUNDARY: {
3174 EmitBoundaryCheck(compiler, trace);
3178 on_success()->Emit(compiler, trace);
3183 if (quick_check ==
NULL)
return false;
3184 if (offset >= quick_check->
characters())
return false;
3190 if (index > *checked_up_to) {
3191 *checked_up_to = index;
3229 bool first_element_checked,
3230 int* checked_up_to) {
3233 bool one_byte = compiler->
one_byte();
3236 int element_count = elms_->length();
3237 for (
int i = preloaded ? 0 : element_count - 1;
i >= 0;
i--) {
3238 TextElement elm = elms_->at(
i);
3240 if (elm.text_type() == TextElement::ATOM) {
3242 for (
int j = preloaded ? 0 : quarks.
length() - 1; j >= 0; j--) {
3243 if (first_element_checked &&
i == 0 && j == 0)
continue;
3247 case NON_LATIN1_MATCH:
3254 case NON_LETTER_CHARACTER_MATCH:
3257 case SIMPLE_CHARACTER_MATCH:
3260 case CASE_CHARACTER_MATCH:
3266 if (emit_function !=
NULL) {
3267 bool bound_checked = emit_function(isolate,
3278 DCHECK_EQ(TextElement::CHAR_CLASS, elm.text_type());
3279 if (pass == CHARACTER_CLASS_MATCH) {
3280 if (first_element_checked &&
i == 0)
continue;
3282 RegExpCharacterClass*
cc = elm.char_class();
3284 *checked_up_to <
cp_offset, preloaded, zone());
3293 TextElement elm = elms_->last();
3294 DCHECK(elm.cp_offset() >= 0);
3295 return elm.cp_offset() + elm.length();
3302 return pass == SIMPLE_CHARACTER_MATCH;
3304 return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH;
3316 LimitResult limit_result = LimitVersions(compiler, trace);
3317 if (limit_result ==
DONE)
return;
3318 DCHECK(limit_result == CONTINUE);
3327 TextEmitPass(compiler, NON_LATIN1_MATCH,
false, trace,
false, &dummy);
3330 bool first_elt_done =
false;
3331 int bound_checked_to = trace->
cp_offset() - 1;
3337 for (
int pass = kFirstRealPass; pass <= kLastPass; pass++) {
3339 TextEmitPass(compiler,
3347 first_elt_done =
true;
3350 for (
int pass = kFirstRealPass; pass <= kLastPass; pass++) {
3352 TextEmitPass(compiler,
3361 Trace successor_trace(*trace);
3365 on_success()->Emit(compiler, &successor_trace);
3394 int element_count = elms_->length();
3395 for (
int i = 0;
i < element_count;
i++) {
3396 TextElement elm = elms_->at(
i);
3397 if (elm.text_type() == TextElement::CHAR_CLASS) {
3398 RegExpCharacterClass*
cc = elm.char_class();
3401 if (
cc->is_standard(zone()))
continue;
3403 int range_count = ranges->length();
3404 for (
int j = 0; j < range_count; j++) {
3405 ranges->
at(j).AddCaseEquivalents(ranges, is_one_byte, zone());
3413 TextElement elm = elms_->at(elms_->length() - 1);
3414 return elm.cp_offset() + elm.length();
3420 if (elms_->length() != 1)
return NULL;
3421 TextElement elm = elms_->at(0);
3422 if (elm.text_type() != TextElement::CHAR_CLASS)
return NULL;
3423 RegExpCharacterClass* node = elm.char_class();
3428 if (node->is_negated()) {
3429 return ranges->length() == 0 ? on_success() :
NULL;
3431 if (ranges->length() != 1)
return NULL;
3438 return ranges->
at(0).IsEverything(max_char) ? on_success() :
NULL;
3452 int recursion_depth = 0;
3453 while (node !=
this) {
3455 return kNodeIsTooComplexForGreedyLoops;
3458 if (node_length == kNodeIsTooComplexForGreedyLoops) {
3459 return kNodeIsTooComplexForGreedyLoops;
3461 length += node_length;
3471 AddAlternative(alt);
3472 loop_node_ = alt.
node();
3478 AddAlternative(alt);
3479 continue_node_ = alt.
node();
3488 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
3489 DCHECK(text_length != kNodeIsTooComplexForGreedyLoops);
3499 trace->
Flush(compiler,
this);
3507 int eats_at_least) {
3508 int preload_characters =
Min(4, eats_at_least);
3510 bool one_byte = compiler->
one_byte();
3512 if (preload_characters > 4) preload_characters = 4;
3516 if (preload_characters == 3) preload_characters = 2;
3518 if (preload_characters > 2) preload_characters = 2;
3521 if (preload_characters > 1) preload_characters = 1;
3523 return preload_characters;
3532 : possible_success(),
3533 expects_preload(
false),
3535 quick_check_details() { }
3548 : alt_gens_(count, zone) {
3549 for (
int i = 0;
i < count &&
i < kAFew;
i++) {
3550 alt_gens_.Add(a_few_alt_gens_ +
i, zone);
3552 for (
int i = kAFew;
i < count;
i++) {
3557 for (
int i = kAFew;
i < alt_gens_.length();
i++) {
3558 delete alt_gens_[
i];
3559 alt_gens_[
i] =
NULL;
3564 return alt_gens_[
i];
3568 static const int kAFew = 10;
3578 0x00A0, 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B,
3579 0x2028, 0x202A, 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001,
3580 0xFEFF, 0xFF00, 0x10000 };
3584 '0',
'9' + 1,
'A',
'Z' + 1,
'_',
'_' + 1,
'a',
'z' + 1, 0x10000 };
3591 0x2028, 0x202A, 0x10000 };
3596 SetInterval(
Interval(character, character));
3606 if (interval.
to() - interval.
from() >= kMapSize - 1) {
3607 if (map_count_ != kMapSize) {
3608 map_count_ = kMapSize;
3609 for (
int i = 0;
i < kMapSize;
i++) map_->at(
i) =
true;
3613 for (
int i = interval.
from();
i <= interval.
to();
i++) {
3614 int mod_character = (
i & kMask);
3615 if (!map_->at(mod_character)) {
3617 map_->at(mod_character) =
true;
3619 if (map_count_ == kMapSize)
return;
3626 if (map_count_ != kMapSize) {
3627 map_count_ = kMapSize;
3628 for (
int i = 0;
i < kMapSize;
i++) map_->at(
i) =
true;
3636 compiler_(compiler) {
3653 int biggest_points = 0;
3656 const int kMaxMax = 32;
3657 for (
int max_number_of_chars = 4;
3658 max_number_of_chars < kMaxMax;
3659 max_number_of_chars *= 2) {
3663 if (biggest_points == 0)
return false;
3675 int max_number_of_chars,
int old_biggest_points,
int* from,
int*
to) {
3676 int biggest_points = old_biggest_points;
3681 int remembered_from =
i;
3682 bool union_map[kSize];
3683 for (
int j = 0; j < kSize; j++) union_map[j] =
false;
3686 for (
int j = 0; j < kSize; j++) union_map[j] |=
map->at(j);
3690 for (
int j = 0; j < kSize; j++) {
3705 bool in_quickcheck_range =
3706 ((
i - remembered_from < 4) ||
3710 int probability = (in_quickcheck_range ? kSize / 2 : kSize) - frequency;
3711 int points = (
i - remembered_from) * probability;
3712 if (points > biggest_points) {
3713 *from = remembered_from;
3715 biggest_points = points;
3718 return biggest_points;
3732 const int kSkipArrayEntry = 0;
3733 const int kDontSkipArrayEntry = 1;
3735 for (
int i = 0;
i < kSize;
i++) {
3736 boolean_skip_table->set(
i, kSkipArrayEntry);
3738 int skip = max_lookahead + 1 - min_lookahead;
3740 for (
int i = max_lookahead;
i >= min_lookahead;
i--) {
3742 for (
int j = 0; j < kSize; j++) {
3744 boolean_skip_table->set(j, kDontSkipArrayEntry);
3757 int min_lookahead = 0;
3758 int max_lookahead = 0;
3762 bool found_single_character =
false;
3763 int single_character = 0;
3764 for (
int i = max_lookahead;
i >= min_lookahead;
i--) {
3766 if (
map->map_count() > 1 ||
3767 (found_single_character &&
map->map_count() != 0)) {
3768 found_single_character =
false;
3771 for (
int j = 0; j < kSize; j++) {
3773 found_single_character =
true;
3774 single_character = j;
3780 int lookahead_width = max_lookahead + 1 - min_lookahead;
3782 if (found_single_character && lookahead_width == 1 && max_lookahead < 3) {
3787 if (found_single_character) {
3807 min_lookahead, max_lookahead, boolean_skip_table);
3808 DCHECK(skip_distance != 0);
3903 for (
int i = 0;
i < choice_count - 1;
i++) {
3906 int guard_count = (guards ==
NULL) ? 0 : guards->length();
3907 for (
int j = 0; j < guard_count; j++) {
3916 Trace* current_trace,
3939 if (limit_result ==
DONE)
return;
3945 trace->
Flush(compiler,
this);
3968 Label second_choice;
3983 int new_flush_budget = trace->
flush_budget() / choice_count;
3984 for (
int i = 0;
i < choice_count;
i++) {
3986 Trace new_trace(*trace);
3993 bool next_expects_preload =
4000 next_expects_preload);
4021 Label greedy_match_failed;
4022 Trace greedy_match_trace;
4026 macro_assembler->
Bind(&loop_label);
4029 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
4030 macro_assembler->
Bind(&greedy_match_failed);
4032 Label second_choice;
4033 macro_assembler->
Bind(&second_choice);
4043 macro_assembler->
Bind(greedy_loop_state->
label());
4048 macro_assembler->
GoTo(&second_choice);
4059 return eats_at_least;
4063 return eats_at_least;
4088 if (eats_at_least >= 1) {
4099 return eats_at_least;
4115 int new_flush_budget = trace->
flush_budget() / choice_count;
4117 for (
int i = first_choice;
i < choice_count;
i++) {
4118 bool is_last =
i == choice_count - 1;
4119 bool fall_through_on_failure = !is_last;
4124 int guard_count = (guards ==
NULL) ? 0 : guards->length();
4125 Trace new_trace(*trace);
4138 bool generate_full_check_inline =
false;
4139 if (FLAG_regexp_optimization &&
4147 fall_through_on_failure)) {
4153 if (!fall_through_on_failure) {
4158 generate_full_check_inline =
true;
4161 if (!fall_through_on_failure) {
4171 if (
i != first_choice) {
4175 generate_full_check_inline =
true;
4177 if (generate_full_check_inline) {
4181 for (
int j = 0; j < guard_count; j++) {
4184 alternative.
node()->
Emit(compiler, &new_trace);
4196 int preload_characters,
4197 bool next_expects_preload) {
4202 Trace out_of_line_trace(*trace);
4207 int guard_count = (guards ==
NULL) ? 0 : guards->length();
4208 if (next_expects_preload) {
4209 Label reload_current_char;
4211 for (
int j = 0; j < guard_count; j++) {
4214 alternative.
node()->
Emit(compiler, &out_of_line_trace);
4215 macro_assembler->
Bind(&reload_current_char);
4222 preload_characters);
4223 macro_assembler->
GoTo(&(alt_gen->
after));
4226 for (
int j = 0; j < guard_count; j++) {
4229 alternative.
node()->
Emit(compiler, &out_of_line_trace);
4237 if (limit_result ==
DONE)
return;
4245 new_capture(
data_.u_position_register.reg,
4246 data_.u_position_register.is_capture,
4248 Trace new_trace = *trace;
4255 new_increment(
data_.u_increment_register.reg);
4256 Trace new_trace = *trace;
4263 new_set(
data_.u_store_register.reg,
data_.u_store_register.value);
4264 Trace new_trace = *trace;
4272 data_.u_clear_captures.range_to));
4273 Trace new_trace = *trace;
4280 trace->
Flush(compiler,
this);
4283 data_.u_submatch.current_position_register, 0);
4285 data_.u_submatch.stack_pointer_register);
4290 int start_pos_reg =
data_.u_empty_match_check.start_register;
4292 int rep_reg =
data_.u_empty_match_check.repetition_register;
4295 if (know_dist && !has_minimum && stored_pos == trace->
cp_offset()) {
4299 }
else if (know_dist && stored_pos < trace->cp_offset()) {
4304 trace->
Flush(compiler,
this);
4306 Label skip_empty_check;
4310 int limit =
data_.u_empty_match_check.repetition_limit;
4311 assembler->
IfRegisterLT(rep_reg, limit, &skip_empty_check);
4317 assembler->
Bind(&skip_empty_check);
4324 trace->
Flush(compiler,
this);
4328 data_.u_submatch.current_position_register);
4330 data_.u_submatch.stack_pointer_register);
4336 int clear_registers_from =
data_.u_submatch.clear_register_from;
4337 Label clear_registers_backtrack;
4338 Trace new_trace = *trace;
4342 assembler->
Bind(&clear_registers_backtrack);
4344 assembler->
ClearRegisters(clear_registers_from, clear_registers_to);
4359 trace->
Flush(compiler,
this);
4364 if (limit_result ==
DONE)
return;
4389 DotPrinter(
OStream& os,
bool ignore_case)
4391 ignore_case_(ignore_case) {}
4392 void PrintNode(
const char* label, RegExpNode* node);
4393 void Visit(RegExpNode* node);
4394 void PrintAttributes(RegExpNode* from);
4395 void PrintOnFailure(RegExpNode* from, RegExpNode*
to);
4396 #define DECLARE_VISIT(Type) \
4397 virtual void Visit##Type(Type##Node* that);
4399 #undef DECLARE_VISIT
4406 void DotPrinter::PrintNode(
const char* label, RegExpNode* node) {
4407 os_ <<
"digraph G {\n graph [label=\"";
4408 for (
int i = 0; label[
i];
i++) {
4427 void DotPrinter::Visit(RegExpNode* node) {
4428 if (node->info()->visited)
return;
4429 node->info()->visited =
true;
4434 void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
4435 os_ <<
" n" << from <<
" -> n" << on_failure <<
" [style=dotted];\n";
4440 class TableEntryBodyPrinter {
4442 TableEntryBodyPrinter(OStream& os, ChoiceNode* choice)
4445 void Call(
uc16 from, DispatchTable::Entry entry) {
4446 OutSet* out_set = entry.out_set();
4448 if (out_set->Get(
i)) {
4449 os_ <<
" n" << choice() <<
":s" << from <<
"o" <<
i <<
" -> n"
4450 << choice()->alternatives()->at(
i).node() <<
";\n";
4455 ChoiceNode* choice() {
return choice_; }
4457 ChoiceNode* choice_;
4461 class TableEntryHeaderPrinter {
4463 explicit TableEntryHeaderPrinter(OStream& os)
4466 void Call(
uc16 from, DispatchTable::Entry entry) {
4472 os_ <<
"{\\" << AsUC16(from) <<
"-\\" << AsUC16(entry.to()) <<
"|{";
4473 OutSet* out_set = entry.out_set();
4476 if (out_set->Get(
i)) {
4477 if (priority > 0) os_ <<
"|";
4478 os_ <<
"<s" << from <<
"o" <<
i <<
"> " << priority;
4491 class AttributePrinter {
4493 explicit AttributePrinter(OStream& os)
4496 void PrintSeparator() {
4503 void PrintBit(
const char*
name,
bool value) {
4506 os_ <<
"{" <<
name <<
"}";
4508 void PrintPositive(
const char*
name,
int value) {
4509 if (value < 0)
return;
4511 os_ <<
"{" <<
name <<
"|" << value <<
"}";
4520 void DotPrinter::PrintAttributes(RegExpNode* that) {
4521 os_ <<
" a" << that <<
" [shape=Mrecord, color=grey, fontcolor=grey, "
4522 <<
"margin=0.1, fontsize=10, label=\"{";
4523 AttributePrinter printer(os_);
4524 NodeInfo* info = that->info();
4525 printer.PrintBit(
"NI", info->follows_newline_interest);
4526 printer.PrintBit(
"WI", info->follows_word_interest);
4527 printer.PrintBit(
"SI", info->follows_start_interest);
4528 Label* label = that->label();
4529 if (label->is_bound())
4530 printer.PrintPositive(
"@", label->pos());
4532 <<
" a" << that <<
" -> n" << that
4533 <<
" [style=dashed, color=grey, arrowhead=none];\n";
4537 static const bool kPrintDispatchTable =
false;
4538 void DotPrinter::VisitChoice(ChoiceNode* that) {
4539 if (kPrintDispatchTable) {
4540 os_ <<
" n" << that <<
" [shape=Mrecord, label=\"";
4541 TableEntryHeaderPrinter header_printer(os_);
4542 that->GetTable(ignore_case_)->ForEach(&header_printer);
4544 PrintAttributes(that);
4545 TableEntryBodyPrinter body_printer(os_, that);
4546 that->GetTable(ignore_case_)->ForEach(&body_printer);
4548 os_ <<
" n" << that <<
" [shape=Mrecord, label=\"?\"];\n";
4549 for (
int i = 0;
i < that->alternatives()->length();
i++) {
4550 GuardedAlternative alt = that->alternatives()->at(
i);
4551 os_ <<
" n" << that <<
" -> n" << alt.node();
4554 for (
int i = 0;
i < that->alternatives()->length();
i++) {
4555 GuardedAlternative alt = that->alternatives()->at(
i);
4556 alt.node()->Accept(
this);
4561 void DotPrinter::VisitText(TextNode* that) {
4562 Zone* zone = that->zone();
4563 os_ <<
" n" << that <<
" [label=\"";
4564 for (
int i = 0;
i < that->elements()->length();
i++) {
4565 if (
i > 0) os_ <<
" ";
4566 TextElement elm = that->elements()->at(
i);
4567 switch (elm.text_type()) {
4568 case TextElement::ATOM: {
4569 Vector<const uc16> data = elm.atom()->data();
4570 for (
int i = 0;
i < data.length();
i++) {
4571 os_ << static_cast<char>(data[
i]);
4575 case TextElement::CHAR_CLASS: {
4576 RegExpCharacterClass* node = elm.char_class();
4578 if (node->is_negated()) os_ <<
"^";
4579 for (
int j = 0; j < node->ranges(zone)->length(); j++) {
4580 CharacterRange range = node->ranges(zone)->at(j);
4581 os_ << AsUC16(range.from()) <<
"-" << AsUC16(range.to());
4590 os_ <<
"\", shape=box, peripheries=2];\n";
4591 PrintAttributes(that);
4592 os_ <<
" n" << that <<
" -> n" << that->on_success() <<
";\n";
4593 Visit(that->on_success());
4597 void DotPrinter::VisitBackReference(BackReferenceNode* that) {
4598 os_ <<
" n" << that <<
" [label=\"$" << that->start_register() <<
"..$"
4599 << that->end_register() <<
"\", shape=doubleoctagon];\n";
4600 PrintAttributes(that);
4601 os_ <<
" n" << that <<
" -> n" << that->on_success() <<
";\n";
4602 Visit(that->on_success());
4606 void DotPrinter::VisitEnd(EndNode* that) {
4607 os_ <<
" n" << that <<
" [style=bold, shape=point];\n";
4608 PrintAttributes(that);
4612 void DotPrinter::VisitAssertion(AssertionNode* that) {
4613 os_ <<
" n" << that <<
" [";
4614 switch (that->assertion_type()) {
4616 os_ <<
"label=\"$\", shape=septagon";
4619 os_ <<
"label=\"^\", shape=septagon";
4622 os_ <<
"label=\"\\b\", shape=septagon";
4625 os_ <<
"label=\"\\B\", shape=septagon";
4628 os_ <<
"label=\"(?<=\\n)\", shape=septagon";
4632 PrintAttributes(that);
4633 RegExpNode* successor = that->on_success();
4634 os_ <<
" n" << that <<
" -> n" << successor <<
";\n";
4639 void DotPrinter::VisitAction(ActionNode* that) {
4640 os_ <<
" n" << that <<
" [";
4641 switch (that->action_type_) {
4643 os_ <<
"label=\"$" << that->data_.u_store_register.reg
4644 <<
":=" << that->data_.u_store_register.value <<
"\", shape=octagon";
4647 os_ <<
"label=\"$" << that->data_.u_increment_register.reg
4648 <<
"++\", shape=octagon";
4651 os_ <<
"label=\"$" << that->data_.u_position_register.reg
4652 <<
":=$pos\", shape=octagon";
4655 os_ <<
"label=\"$" << that->data_.u_submatch.current_position_register
4656 <<
":=$pos,begin\", shape=septagon";
4659 os_ <<
"label=\"escape\", shape=septagon";
4662 os_ <<
"label=\"$" << that->data_.u_empty_match_check.start_register
4663 <<
"=$pos?,$" << that->data_.u_empty_match_check.repetition_register
4664 <<
"<" << that->data_.u_empty_match_check.repetition_limit
4665 <<
"?\", shape=septagon";
4668 os_ <<
"label=\"clear $" << that->data_.u_clear_captures.range_from
4669 <<
" to $" << that->data_.u_clear_captures.range_to
4670 <<
"\", shape=septagon";
4675 PrintAttributes(that);
4676 RegExpNode* successor = that->on_success();
4677 os_ <<
" n" << that <<
" -> n" << successor <<
";\n";
4682 class DispatchTableDumper {
4684 explicit DispatchTableDumper(OStream& os) : os_(os) {}
4685 void Call(
uc16 key, DispatchTable::Entry entry);
4691 void DispatchTableDumper::Call(
uc16 key, DispatchTable::Entry entry) {
4692 os_ <<
"[" << AsUC16(key) <<
"-" << AsUC16(entry.to()) <<
"]: {";
4693 OutSet* set = entry.out_set();
4710 OFStream os(stderr);
4711 DispatchTableDumper dumper(os);
4712 tree()->ForEach(&dumper);
4719 OFStream os(stdout);
4720 DotPrinter printer(os, ignore_case);
4721 printer.PrintNode(label, node);
4731 RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
4732 RegExpNode* on_success) {
4733 ZoneList<TextElement>* elms =
4734 new(compiler->zone()) ZoneList<TextElement>(1, compiler->zone());
4735 elms->Add(TextElement::Atom(
this), compiler->zone());
4736 return new(compiler->zone()) TextNode(elms, on_success);
4740 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
4741 RegExpNode* on_success) {
4742 return new(compiler->zone()) TextNode(elements(), on_success);
4747 const int* special_class,
4750 DCHECK(special_class[length] == 0x10000);
4751 DCHECK(ranges->length() != 0);
4753 DCHECK(special_class[0] != 0);
4754 if (ranges->length() != (length >> 1) + 1) {
4758 if (range.
from() != 0) {
4761 for (
int i = 0;
i < length;
i += 2) {
4762 if (special_class[
i] != (range.
to() + 1)) {
4765 range = ranges->
at((
i >> 1) + 1);
4766 if (special_class[
i+1] != range.
from()) {
4770 if (range.
to() != 0xffff) {
4778 const int* special_class,
4781 DCHECK(special_class[length] == 0x10000);
4782 if (ranges->length() * 2 != length) {
4785 for (
int i = 0;
i < length;
i += 2) {
4787 if (range.
from() != special_class[
i] ||
4788 range.
to() != special_class[
i + 1] - 1) {
4796 bool RegExpCharacterClass::is_standard(Zone* zone) {
4802 if (set_.is_standard()) {
4806 set_.set_standard_set_type(
's');
4810 set_.set_standard_set_type(
'S');
4816 set_.set_standard_set_type(
'.');
4822 set_.set_standard_set_type(
'n');
4826 set_.set_standard_set_type(
'w');
4830 set_.set_standard_set_type(
'W');
4837 RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
4838 RegExpNode* on_success) {
4839 return new(compiler->zone()) TextNode(
this, on_success);
4843 RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
4844 RegExpNode* on_success) {
4845 ZoneList<RegExpTree*>* alternatives = this->alternatives();
4846 int length = alternatives->length();
4847 ChoiceNode* result =
4848 new(compiler->zone()) ChoiceNode(length, compiler->zone());
4849 for (
int i = 0;
i < length;
i++) {
4850 GuardedAlternative alternative(alternatives->at(
i)->ToNode(compiler,
4852 result->AddAlternative(alternative);
4858 RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler,
4859 RegExpNode* on_success) {
4860 return ToNode(
min(),
4913 bool not_at_start) {
4934 static const int kMaxUnrolledMinMatches = 3;
4935 static const int kMaxUnrolledMaxMatches = 3;
4936 if (max == 0)
return on_success;
4937 bool body_can_be_empty = (body->
min_match() == 0);
4940 bool needs_capture_clearing = !capture_registers.
is_empty();
4943 if (body_can_be_empty) {
4945 }
else if (FLAG_regexp_optimization && !needs_capture_clearing) {
4949 RegExpExpansionLimiter limiter(
4950 compiler,
min + ((max !=
min) ? 1 : 0));
4951 if (
min > 0 &&
min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) {
4952 int new_max = (max == kInfinity) ? max : max -
min;
4955 RegExpNode* answer = ToNode(
4956 0, new_max, is_greedy, body, compiler, on_success,
true);
4960 for (
int i = 0;
i <
min;
i++) {
4961 answer = body->
ToNode(compiler, answer);
4966 if (max <= kMaxUnrolledMaxMatches &&
min == 0) {
4968 RegExpExpansionLimiter limiter(compiler, max);
4969 if (limiter.ok_to_expand()) {
4971 RegExpNode* answer = on_success;
4972 for (
int i = 0;
i < max;
i++) {
4973 ChoiceNode* alternation =
new(zone) ChoiceNode(2, zone);
4975 alternation->AddAlternative(
4976 GuardedAlternative(body->
ToNode(compiler, answer)));
4977 alternation->AddAlternative(GuardedAlternative(on_success));
4979 alternation->AddAlternative(GuardedAlternative(on_success));
4980 alternation->AddAlternative(
4981 GuardedAlternative(body->
ToNode(compiler, answer)));
4983 answer = alternation;
4984 if (not_at_start) alternation->set_not_at_start();
4990 bool has_min =
min > 0;
4992 bool needs_counter = has_min || has_max;
4993 int reg_ctr = needs_counter
4996 LoopChoiceNode* center =
new(zone) LoopChoiceNode(body->
min_match() == 0,
4998 if (not_at_start) center->set_not_at_start();
4999 RegExpNode* loop_return = needs_counter
5001 :
static_cast<RegExpNode*
>(center);
5002 if (body_can_be_empty) {
5010 RegExpNode* body_node = body->
ToNode(compiler, loop_return);
5011 if (body_can_be_empty) {
5016 if (needs_capture_clearing) {
5020 GuardedAlternative body_alt(body_node);
5023 new(zone) Guard(reg_ctr,
Guard::LT, max);
5024 body_alt.AddGuard(body_guard, zone);
5026 GuardedAlternative rest_alt(on_success);
5029 rest_alt.AddGuard(rest_guard, zone);
5032 center->AddLoopAlternative(body_alt);
5033 center->AddContinueAlternative(rest_alt);
5035 center->AddContinueAlternative(rest_alt);
5036 center->AddLoopAlternative(body_alt);
5038 if (needs_counter) {
5046 RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
5047 RegExpNode* on_success) {
5049 Zone* zone = compiler->zone();
5051 switch (assertion_type()) {
5054 case START_OF_INPUT:
5066 int stack_pointer_register = compiler->AllocateRegister();
5067 int position_register = compiler->AllocateRegister();
5069 ChoiceNode* result =
new(zone) ChoiceNode(2, zone);
5071 ZoneList<CharacterRange>* newline_ranges =
5072 new(zone) ZoneList<CharacterRange>(3, zone);
5074 RegExpCharacterClass* newline_atom =
new(zone) RegExpCharacterClass(
'n');
5075 TextNode* newline_matcher =
new(zone) TextNode(
5084 stack_pointer_register,
5088 GuardedAlternative eol_alternative(end_of_line);
5089 result->AddAlternative(eol_alternative);
5091 result->AddAlternative(end_alternative);
5101 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
5102 RegExpNode* on_success) {
5103 return new(compiler->zone())
5104 BackReferenceNode(RegExpCapture::StartRegister(index()),
5105 RegExpCapture::EndRegister(index()),
5110 RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
5111 RegExpNode* on_success) {
5116 RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
5117 RegExpNode* on_success) {
5118 int stack_pointer_register = compiler->AllocateRegister();
5119 int position_register = compiler->AllocateRegister();
5121 const int registers_per_capture = 2;
5122 const int register_of_first_capture = 2;
5123 int register_count = capture_count_ * registers_per_capture;
5124 int register_start =
5125 register_of_first_capture + capture_from_ * registers_per_capture;
5127 RegExpNode* success;
5128 if (is_positive()) {
5130 stack_pointer_register,
5151 Zone* zone = compiler->zone();
5153 GuardedAlternative body_alt(
5156 success =
new(zone) NegativeSubmatchSuccess(stack_pointer_register,
5161 ChoiceNode* choice_node =
5162 new(zone) NegativeLookaheadChoiceNode(body_alt,
5163 GuardedAlternative(on_success),
5172 RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler,
5173 RegExpNode* on_success) {
5174 return ToNode(body(), index(), compiler, on_success);
5178 RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
5180 RegExpCompiler* compiler,
5181 RegExpNode* on_success) {
5182 int start_reg = RegExpCapture::StartRegister(index);
5183 int end_reg = RegExpCapture::EndRegister(index);
5185 RegExpNode* body_node = body->ToNode(compiler, store_end);
5190 RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
5191 RegExpNode* on_success) {
5192 ZoneList<RegExpTree*>* children = nodes();
5193 RegExpNode* current = on_success;
5194 for (
int i = children->length() - 1;
i >= 0;
i--) {
5195 current = children->at(
i)->ToNode(compiler, current);
5206 DCHECK(elmv[elmc] == 0x10000);
5207 for (
int i = 0;
i < elmc;
i += 2) {
5219 DCHECK(elmv[elmc] == 0x10000);
5220 DCHECK(elmv[0] != 0x0000);
5223 for (
int i = 0;
i < elmc;
i += 2) {
5324 for (
int i = 0;
i < base->length();
i++)
5326 for (
int i = 0;
i < overlay.
length();
i += 2) {
5336 bool is_one_byte,
Zone* zone) {
5345 if (top == bottom) {
5348 for (
int i = 0;
i < length;
i++) {
5349 uc32 chr = chars[
i];
5350 if (chr != bottom) {
5375 while (pos <= top) {
5382 block_end = range[0];
5384 int end = (block_end > top) ? top : block_end;
5386 for (
int i = 0;
i < length;
i++) {
5388 uc16 range_from = c - (block_end - pos);
5389 uc16 range_to = c - (block_end - end);
5390 if (!(bottom <= range_from && range_to <= top)) {
5402 int n = ranges->length();
5403 if (n <= 1)
return true;
5404 int max = ranges->
at(0).to();
5405 for (
int i = 1;
i < n;
i++) {
5407 if (next_range.
from() <= max + 1)
return false;
5408 max = next_range.
to();
5415 if (ranges_ ==
NULL) {
5431 for (
int i = count - 1;
i >= 0;
i--) {
5432 list->
at(
to +
i) = list->
at(from +
i);
5435 for (
int i = 0;
i < count;
i++) {
5436 list->
at(
to +
i) = list->
at(from +
i);
5453 int end_pos = count;
5454 for (
int i = count - 1;
i >= 0;
i--) {
5456 if (current.
from() >
to + 1) {
5458 }
else if (current.
to() + 1 < from) {
5471 if (start_pos == end_pos) {
5473 if (start_pos < count) {
5474 MoveRanges(list, start_pos, start_pos + 1, count - start_pos);
5476 list->
at(start_pos) = insert;
5479 if (start_pos + 1 == end_pos) {
5482 int new_from =
Min(to_replace.
from(), from);
5483 int new_to =
Max(to_replace.
to(),
to);
5490 int new_from =
Min(list->
at(start_pos).from(), from);
5491 int new_to =
Max(list->
at(end_pos - 1).to(),
to);
5492 if (end_pos < count) {
5493 MoveRanges(list, end_pos, start_pos + 1, count - end_pos);
5496 return count - (end_pos - start_pos) + 1;
5503 if (ranges_ ==
NULL)
return;
5509 if (character_ranges->length() <= 1)
return;
5512 int n = character_ranges->length();
5513 int max = character_ranges->
at(0).to();
5517 if (current.
from() <= max + 1) {
5532 int num_canonical =
i;
5536 character_ranges->
at(read));
5539 character_ranges->Rewind(num_canonical);
5550 int range_count = ranges->length();
5553 if (range_count > 0 && ranges->
at(0).from() == 0) {
5554 from = ranges->
at(0).to();
5557 while (
i < range_count) {
5580 if (successor->
Get(value))
5587 result->
Set(value, zone);
5607 return (
first_ & (1 << value)) != 0;
5622 if (
tree()->is_empty()) {
5633 if (
tree()->FindGreatestLessThan(current.
from(), &loc)) {
5634 Entry* entry = &loc.value();
5639 if (entry->
from() < current.
from() && entry->
to() >= current.
from()) {
5658 if (
tree()->FindLeastGreaterThan(current.
from(), &loc) &&
5659 (loc.value().from() <= current.
to()) &&
5660 (loc.value().to() >= current.
from())) {
5661 Entry* entry = &loc.value();
5665 if (current.
from() < entry->
from()) {
5676 if (entry->
to() > current.
to()) {
5679 ins.set_value(
Entry(current.
to() + 1,
5710 if (!
tree()->FindGreatestLessThan(value, &loc))
5712 Entry* entry = &loc.value();
5713 if (value <= entry->
to())
5726 if (check.HasOverflowed()) {
5727 fail(
"Stack overflow");
5739 void Analysis::VisitEnd(
EndNode* that) {
5745 int element_count =
elements()->length();
5749 for (
int i = 0;
i < element_count;
i++) {
5751 elm.set_cp_offset(cp_offset);
5752 cp_offset += elm.length();
5757 void Analysis::VisitText(
TextNode* that) {
5768 void Analysis::VisitAction(ActionNode* that) {
5769 RegExpNode* target = that->on_success();
5774 that->info()->AddFromFollowing(target->info());
5779 void Analysis::VisitChoice(ChoiceNode* that) {
5780 NodeInfo* info = that->info();
5781 for (
int i = 0;
i < that->alternatives()->length();
i++) {
5782 RegExpNode* node = that->alternatives()->at(
i).node();
5787 info->AddFromFollowing(node->info());
5816 void Analysis::VisitAssertion(AssertionNode* that) {
5824 bool not_at_start) {
5839 bool not_at_start) {
5841 budget = (budget - 1) / alts->length();
5842 for (
int i = 0;
i < alts->length();
i++) {
5858 bool not_at_start) {
5859 if (initial_offset >= bm->
length())
return;
5860 int offset = initial_offset;
5863 if (offset >= bm->
length()) {
5864 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5868 if (text.text_type() == TextElement::ATOM) {
5869 RegExpAtom* atom = text.atom();
5870 for (
int j = 0; j < atom->length(); j++, offset++) {
5871 if (offset >= bm->
length()) {
5872 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5875 uc16 character = atom->data()[j];
5883 for (
int j = 0; j < length; j++) {
5884 bm->
Set(offset, chars[j]);
5887 if (character <= max_char) bm->
Set(offset, character);
5891 DCHECK_EQ(TextElement::CHAR_CLASS, text.text_type());
5892 RegExpCharacterClass* char_class = text.char_class();
5894 if (char_class->is_negated()) {
5897 for (
int k = 0; k < ranges->length(); k++) {
5899 if (range.
from() > max_char)
continue;
5900 int to =
Min(max_char,
static_cast<int>(range.
to()));
5907 if (offset >= bm->
length()) {
5908 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5915 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5923 void DispatchTableConstructor::VisitEnd(
EndNode* that) {
5931 for (
int i = 0;
i < alternatives->length();
i++) {
5933 alternatives->
at(
i).node()->Accept(
this);
5955 void DispatchTableConstructor::VisitChoice(
ChoiceNode* node) {
5964 void DispatchTableConstructor::VisitBackReference(BackReferenceNode* that) {
5971 void DispatchTableConstructor::VisitAssertion(AssertionNode* that) {
5972 RegExpNode* target = that->on_success();
5973 target->Accept(
this);
5979 return Compare<uc16>(a->
from(), b->
from());
5986 for (
int i = 0;
i < ranges->length();
i++) {
5988 if (last < range.
from())
5990 if (range.
to() >= last) {
5994 last = range.
to() + 1;
6002 void DispatchTableConstructor::VisitText(
TextNode* that) {
6004 switch (elm.text_type()) {
6005 case TextElement::ATOM: {
6006 uc16 c = elm.atom()->data()[0];
6010 case TextElement::CHAR_CLASS: {
6011 RegExpCharacterClass* tree = elm.char_class();
6012 ZoneList<CharacterRange>* ranges = tree->ranges(that->
zone());
6013 if (tree->is_negated()) {
6016 for (
int i = 0;
i < ranges->length();
i++)
6028 void DispatchTableConstructor::VisitAction(ActionNode* that) {
6029 RegExpNode* target = that->on_success();
6030 target->Accept(
this);
6044 static const int kSampleSize = 128;
6047 int chars_sampled = 0;
6048 int half_way = (sample_subject->length() - kSampleSize) / 2;
6049 for (
int i =
Max(0, half_way);
6050 i < sample_subject->length() && chars_sampled < kSampleSize;
6051 i++, chars_sampled++) {
6064 if (!is_start_anchored && !is_sticky) {
6068 RegExpQuantifier::ToNode(0,
6071 new(zone) RegExpCharacterClass(
'*'),
6082 new(zone)
TextNode(
new(zone) RegExpCharacterClass(
'*'), loop_node)));
6083 node = first_step_node;
6099 Analysis analysis(ignore_case, is_one_byte);
6107 #ifndef V8_INTERPRETED_REGEXP
6114 #if V8_TARGET_ARCH_IA32
6117 #elif V8_TARGET_ARCH_X64
6120 #elif V8_TARGET_ARCH_ARM
6123 #elif V8_TARGET_ARCH_ARM64
6126 #elif V8_TARGET_ARCH_MIPS
6129 #elif V8_TARGET_ARCH_MIPS64
6132 #elif V8_TARGET_ARCH_X87
6136 #error "Unsupported architecture"
6142 RegExpMacroAssemblerIrregexp macro_assembler(codes, zone);
6147 static const int kMaxBacksearchLimit = 1024;
6148 if (is_end_anchored &&
6149 !is_start_anchored &&
6150 max_length < kMaxBacksearchLimit) {
6161 return compiler.
Assemble(¯o_assembler,
#define DECLARE_VISIT(type)
static uint16_t ConvertNonLatin1ToLatin1(uint16_t)
int get(uchar c, uchar n, uchar *result)
static const uchar kBadChar
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
struct v8::internal::ActionNode::@22::@28 u_clear_captures
struct v8::internal::ActionNode::@22::@23 u_store_register
static ActionNode * EmptyMatchCheck(int start_register, int repetition_register, int repetition_limit, RegExpNode *on_success)
union v8::internal::ActionNode::@22 data_
static ActionNode * StorePosition(int reg, bool is_capture, RegExpNode *on_success)
static ActionNode * BeginSubmatch(int stack_pointer_reg, int position_reg, RegExpNode *on_success)
static ActionNode * PositiveSubmatchSuccess(int stack_pointer_reg, int restore_reg, int clear_capture_count, int clear_capture_from, RegExpNode *on_success)
static ActionNode * SetRegister(int reg, int val, RegExpNode *on_success)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
@ POSITIVE_SUBMATCH_SUCCESS
static ActionNode * IncrementRegister(int reg, RegExpNode *on_success)
struct v8::internal::ActionNode::@22::@25 u_position_register
struct v8::internal::ActionNode::@22::@24 u_increment_register
struct v8::internal::ActionNode::@22::@27 u_empty_match_check
static ActionNode * ClearCaptures(Interval range, RegExpNode *on_success)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
struct v8::internal::ActionNode::@22::@26 u_submatch
void Call(uc32 from, DispatchTable::Entry entry)
AddDispatchRange(DispatchTableConstructor *constructor)
DispatchTableConstructor * constructor_
AlternativeGeneration * at(int i)
AlternativeGenerationList(int count, Zone *zone)
~AlternativeGenerationList()
ZoneList< AlternativeGeneration * > alt_gens_
QuickCheckDetails quick_check_details
const char * error_message()
void EnsureAnalyzed(RegExpNode *node)
virtual void VisitLoopChoice(LoopChoiceNode *that)
void fail(const char *error_message)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
void EmitBoundaryCheck(RegExpCompiler *compiler, Trace *trace)
static AssertionNode * AtEnd(RegExpNode *on_success)
static AssertionNode * AfterNewline(RegExpNode *on_success)
static AssertionNode * AtBoundary(RegExpNode *on_success)
static AssertionNode * AtStart(RegExpNode *on_success)
void BacktrackIfPrevious(RegExpCompiler *compiler, Trace *trace, IfPrevious backtrack_if_previous)
static AssertionNode * AtNonBoundary(RegExpNode *on_success)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int filled_in, bool not_at_start)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual int EatsAtLeast(int still_to_find, int recursion_depth, bool not_at_start)
int GetSkipTable(int min_lookahead, int max_lookahead, Handle< ByteArray > boolean_skip_table)
void SetInterval(int map_number, const Interval &interval)
ZoneList< BoyerMoorePositionInfo * > * bitmaps_
void SetAll(int map_number)
int Count(int map_number)
RegExpCompiler * compiler_
BoyerMoorePositionInfo * at(int i)
void SetRest(int from_map)
RegExpCompiler * compiler()
BoyerMooreLookahead(int length, RegExpCompiler *compiler, Zone *zone)
bool FindWorthwhileInterval(int *from, int *to)
int FindBestInterval(int max_number_of_chars, int old_biggest_points, int *from, int *to)
void EmitSkipInstructions(RegExpMacroAssembler *masm)
void Set(int map_number, int character)
void SetInterval(const Interval &interval)
static const int kMapSize
void Call(uc16 from, DispatchTable::Entry entry)
ZoneList< CharacterRange > ** excluded_
CharacterRangeSplitter(ZoneList< CharacterRange > **included, ZoneList< CharacterRange > **excluded, Zone *zone)
ZoneList< CharacterRange > ** included_
static const int kInOverlay
static void Split(ZoneList< CharacterRange > *base, Vector< const int > overlay, ZoneList< CharacterRange > **included, ZoneList< CharacterRange > **excluded, Zone *zone)
static void Canonicalize(ZoneList< CharacterRange > *ranges)
void set_from(uc16 value)
void AddCaseEquivalents(ZoneList< CharacterRange > *ranges, bool is_one_byte, Zone *zone)
static Vector< const int > GetWordBounds()
static CharacterRange Singleton(uc16 value)
static void Negate(ZoneList< CharacterRange > *src, ZoneList< CharacterRange > *dst, Zone *zone)
static bool IsCanonical(ZoneList< CharacterRange > *ranges)
static CharacterRange Everything()
static void AddClassEscape(uc16 type, ZoneList< CharacterRange > *ranges, Zone *zone)
int EmitOptimizedUnanchoredSearch(RegExpCompiler *compiler, Trace *trace)
DispatchTable * GetTable(bool ignore_case)
ZoneList< GuardedAlternative > * alternatives()
ZoneList< GuardedAlternative > * alternatives_
void AddAlternative(GuardedAlternative node)
int GreedyLoopTextLengthForAlternative(GuardedAlternative *alternative)
int CalculatePreloadCharacters(RegExpCompiler *compiler, int eats_at_least)
Trace * EmitGreedyLoop(RegExpCompiler *compiler, Trace *trace, AlternativeGenerationList *alt_gens, PreloadState *preloads, GreedyLoopState *greedy_loop_state, int text_length)
void set_being_calculated(bool b)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
virtual bool try_to_emit_quick_check_for_alternative(bool is_first)
void EmitChoices(RegExpCompiler *compiler, AlternativeGenerationList *alt_gens, int first_choice, Trace *trace, PreloadState *preloads)
void EmitOutOfLineContinuation(RegExpCompiler *compiler, Trace *trace, GuardedAlternative alternative, AlternativeGeneration *alt_gen, int preload_characters, bool next_expects_preload)
void SetUpPreLoad(RegExpCompiler *compiler, Trace *current_trace, PreloadState *preloads)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
void AssertGuardsMentionRegisters(Trace *trace)
void GenerateGuard(RegExpMacroAssembler *macro_assembler, Guard *guard, Trace *trace)
int EatsAtLeastHelper(int still_to_find, int budget, RegExpNode *ignore_this_node, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
MaybeHandle< FixedArray > LookupRegExp(Handle< String > source, JSRegExp::Flags flags)
void PutRegExp(Handle< String > source, JSRegExp::Flags flags, Handle< FixedArray > data)
void AddRange(CharacterRange range)
void BuildTable(ChoiceNode *node)
void AddInverse(ZoneList< CharacterRange > *ranges)
void set_choice_index(int value)
void AddValue(int value, Zone *zone)
void AddRange(CharacterRange range, int value, Zone *zone)
void ForEach(Callback *callback)
ZoneSplayTree< Config > * tree()
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
void set(int index, Object *value)
CharacterFrequency(int character)
int Frequency(int in_character)
void CountCharacter(int character)
Trace * counter_backtrack_trace()
Trace counter_backtrack_trace_
GreedyLoopState(bool not_at_start)
void AddGuard(Guard *guard, Zone *zone)
ZoneList< Guard * > * guards()
static Handle< T > cast(Handle< S > that)
Isolate * GetIsolate() const
void IncreaseTotalRegexpCodeGenerated(int size)
double total_regexp_code_generated()
static RegExpImpl::IrregexpResult Match(Isolate *isolate, Handle< ByteArray > code, Handle< String > subject, int *captures, int start_position)
unibrow::Mapping< unibrow::CanonicalizationRange > * jsregexp_canonrange()
MemoryAllocator * memory_allocator()
Object * Throw(Object *exception, MessageLocation *location=NULL)
CodeTracer * GetCodeTracer()
unibrow::Mapping< unibrow::Ecma262UnCanonicalize > * jsregexp_uncanonicalize()
CompilationCache * compilation_cache()
static const int kJSRegexpStaticOffsetsVectorSize
bool has_pending_exception()
static void EnsureSize(Handle< JSArray > array, int minimum_size_of_backing_fixed_array)
static const int kUninitializedValue
static const int kIrregexpCaptureCountIndex
static const int kCompilationErrorValue
static const int kAtomPatternIndex
static const int kIrregexpMaxRegisterCountIndex
static int saved_code_index(bool is_latin1)
static int code_index(bool is_latin1)
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
void Sort(int(*cmp)(const T *x, const T *y))
bool Contains(const T &elm) const
void AddContinueAlternative(GuardedAlternative alt)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
void AddLoopAlternative(GuardedAlternative alt)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void Accept(NodeVisitor *visitor)
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
intptr_t SizeExecutable()
static Result Match(Handle< Code > regexp, Handle< String > subject, int *offsets_vector, int offsets_vector_length, int previous_index, Isolate *isolate)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void VisitLoopChoice(LoopChoiceNode *that)
void Set(unsigned value, Zone *zone)
OutSet * Extend(unsigned value, Zone *zone)
ZoneList< unsigned > * remaining_
ZoneList< OutSet * > * successors_
bool Get(unsigned value) const
static const unsigned kFirstLimit
ZoneList< OutSet * > * successors(Zone *zone)
Position * positions(int index)
void Merge(QuickCheckDetails *other, int from_index)
void set_characters(int characters)
bool Rationalize(bool one_byte)
void Advance(int by, bool one_byte)
RecursionCheck(RegExpCompiler *compiler)
RegExpCompiler * compiler_
static const int kMaxRecursion
FrequencyCollator frequency_collator_
void IncrementRecursionDepth()
int current_expansion_factor_
static const int kNoRegister
void set_current_expansion_factor(int value)
RegExpEngine::CompilationResult Assemble(RegExpMacroAssembler *assembler, RegExpNode *start, int capture_count, Handle< String > pattern)
RegExpCompiler(int capture_count, bool ignore_case, bool is_one_byte, Zone *zone)
RegExpMacroAssembler * macro_assembler()
List< RegExpNode * > * work_list_
RegExpMacroAssembler * macro_assembler_
FrequencyCollator * frequency_collator()
int current_expansion_factor()
void AddWork(RegExpNode *node)
void DecrementRecursionDepth()
static CompilationResult Compile(RegExpCompileData *input, bool ignore_case, bool global, bool multiline, bool sticky, Handle< String > pattern, Handle< String > sample_subject, bool is_one_byte, Zone *zone)
static void DotPrint(const char *label, RegExpNode *node, bool ignore_case)
DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpExpansionLimiter)
RegExpExpansionLimiter(RegExpCompiler *compiler, int factor)
int saved_expansion_factor_
~RegExpExpansionLimiter()
static const int kMaxExpansionFactor
RegExpCompiler * compiler_
Handle< String > subject_
int32_t * register_array_
Handle< JSRegExp > regexp_
GlobalCache(Handle< JSRegExp > regexp, Handle< String > subject, bool is_global, Isolate *isolate)
static const int kRegWxpCompiledLimit
static MUST_USE_RESULT MaybeHandle< Object > Exec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
static MUST_USE_RESULT MaybeHandle< Object > IrregexpExec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
static void SetLastCaptureCount(FixedArray *array, int to)
static void SetIrregexpMaxRegisterCount(FixedArray *re, int value)
static bool CompileIrregexp(Handle< JSRegExp > re, Handle< String > sample_subject, bool is_one_byte)
static void SetLastSubject(FixedArray *array, String *to)
static Handle< Object > AtomExec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
static void AtomCompile(Handle< JSRegExp > re, Handle< String > pattern, JSRegExp::Flags flags, Handle< String > match_pattern)
static const int kLastMatchOverhead
static void SetCapture(FixedArray *array, int index, int to)
static ByteArray * IrregexpByteCode(FixedArray *re, bool is_one_byte)
static Handle< JSArray > SetLastMatchInfo(Handle< JSArray > last_match_info, Handle< String > subject, int capture_count, int32_t *match)
static int AtomExecRaw(Handle< JSRegExp > regexp, Handle< String > subject, int index, int32_t *output, int output_size)
static void IrregexpInitialize(Handle< JSRegExp > re, Handle< String > pattern, JSRegExp::Flags flags, int capture_register_count)
static int IrregexpMaxRegisterCount(FixedArray *re)
static const int kRegExpExecutableMemoryLimit
static MUST_USE_RESULT MaybeHandle< Object > CreateRegExpLiteral(Handle< JSFunction > constructor, Handle< String > pattern, Handle< String > flags)
static void SetLastInput(FixedArray *array, String *to)
static int IrregexpPrepare(Handle< JSRegExp > regexp, Handle< String > subject)
static int IrregexpExecRaw(Handle< JSRegExp > regexp, Handle< String > subject, int index, int32_t *output, int output_size)
static Code * IrregexpNativeCode(FixedArray *re, bool is_one_byte)
static int IrregexpNumberOfRegisters(FixedArray *re)
static bool EnsureCompiledIrregexp(Handle< JSRegExp > re, Handle< String > sample_subject, bool is_one_byte)
static int IrregexpNumberOfCaptures(FixedArray *re)
static MUST_USE_RESULT MaybeHandle< Object > Compile(Handle< JSRegExp > re, Handle< String > pattern, Handle< String > flags)
virtual void SetCurrentPositionFromEnd(int by)
virtual void LoadCurrentCharacter(int cp_offset, Label *on_end_of_input, bool check_bounds=true, int characters=1)=0
virtual void CheckBitInTable(Handle< ByteArray > table, Label *on_bit_set)=0
virtual void PushRegister(int register_index, StackCheckFlag check_stack_limit)=0
virtual void Bind(Label *label)=0
virtual void PushBacktrack(Label *label)=0
virtual void IfRegisterEqPos(int reg, Label *if_eq)=0
virtual void CheckPosition(int cp_offset, Label *on_outside_input)
void set_global_mode(GlobalMode mode)
virtual void SetRegister(int register_index, int to)=0
void set_slow_safe(bool ssc)
virtual bool CheckSpecialCharacterClass(uc16 type, Label *on_no_match)
virtual void Backtrack()=0
virtual void CheckAtStart(Label *on_at_start)=0
virtual void CheckCharacterNotInRange(uc16 from, uc16 to, Label *on_not_in_range)=0
virtual void CheckCharacterAfterAnd(unsigned c, unsigned and_with, Label *on_equal)=0
virtual void CheckCharacterLT(uc16 limit, Label *on_less)=0
virtual void CheckNotCharacterAfterMinusAnd(uc16 c, uc16 minus, uc16 and_with, Label *on_not_equal)=0
virtual void CheckNotBackReference(int start_reg, Label *on_no_match)=0
virtual void CheckCharacter(unsigned c, Label *on_equal)=0
virtual void ReadCurrentPositionFromRegister(int reg)=0
virtual void CheckCharacterGT(uc16 limit, Label *on_greater)=0
static const int kTableSizeBits
virtual void CheckCharacterInRange(uc16 from, uc16 to, Label *on_in_range)=0
@ GLOBAL_NO_ZERO_LENGTH_CHECK
virtual void IfRegisterLT(int reg, int comparand, Label *if_lt)=0
static const int kTableMask
virtual void PushCurrentPosition()=0
virtual void ReadStackPointerFromRegister(int reg)=0
static const int kMaxRegister
static const int kMaxCPOffset
virtual void WriteStackPointerToRegister(int reg)=0
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset)=0
virtual void CheckGreedyLoop(Label *on_tos_equals_current_position)=0
virtual Handle< HeapObject > GetCode(Handle< String > source)=0
virtual void AdvanceCurrentPosition(int by)=0
virtual bool CanReadUnaligned()=0
virtual int stack_limit_slack()=0
virtual void PopRegister(int register_index)=0
virtual void PopCurrentPosition()=0
virtual void CheckNotBackReferenceIgnoreCase(int start_reg, Label *on_no_match)=0
virtual void CheckNotCharacter(unsigned c, Label *on_not_equal)=0
virtual void GoTo(Label *label)=0
virtual void AdvanceRegister(int reg, int by)=0
static const int kTableSize
virtual void ClearRegisters(int reg_from, int reg_to)=0
virtual void IfRegisterGE(int reg, int comparand, Label *if_ge)=0
virtual void CheckNotAtStart(Label *on_not_at_start)=0
virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, Label *on_not_equal)=0
BoyerMooreLookahead * bm_info(bool not_at_start)
void set_bm_info(bool not_at_start, BoyerMooreLookahead *bm)
virtual RegExpNode * GetSuccessorOfOmnivorousTextNode(RegExpCompiler *compiler)
LimitResult LimitVersions(RegExpCompiler *compiler, Trace *trace)
void SaveBMInfo(BoyerMooreLookahead *bm, bool not_at_start, int offset)
bool EmitQuickCheck(RegExpCompiler *compiler, Trace *bounds_check_trace, Trace *trace, bool preload_has_checked_bounds, Label *on_possible_success, QuickCheckDetails *details_return, bool fall_through_on_failure)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual int GreedyLoopTextLength()
virtual void Emit(RegExpCompiler *compiler, Trace *trace)=0
virtual void Accept(NodeVisitor *visitor)=0
static const int kRecursionBudget
static const int kNodeIsTooComplexForGreedyLoops
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)=0
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)=0
virtual bool IsAnchoredAtStart()
virtual bool IsAnchoredAtEnd()
virtual int min_match()=0
virtual void AppendToText(RegExpText *text, Zone *zone)
static const int kInfinity
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)=0
virtual Interval CaptureRegisters()
virtual int max_match()=0
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
RegExpNode * FilterSuccessor(int depth, bool ignore_case)
RegExpNode * on_success()
static Smi * FromInt(int value)
Vector< const uint8_t > ToOneByteVector()
Vector< const uc16 > ToUC16Vector()
FlatContent GetFlatContent()
static const uint32_t kMaxOneByteCharCodeU
static const int32_t kMaxOneByteCharCode
static const int kMaxUtf16CodeUnit
SmartArrayPointer< char > ToCString(AllowNullsFlag allow_nulls, RobustnessFlag robustness_flag, int offset, int length, int *length_output=0)
static Handle< String > Flatten(Handle< String > string, PretenureFlag pretenure=NOT_TENURED)
static bool SkipPass(int pass, bool ignore_case)
virtual int GreedyLoopTextLength()
virtual RegExpNode * GetSuccessorOfOmnivorousTextNode(RegExpCompiler *compiler)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
void MakeCaseIndependent(bool is_one_byte)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
void TextEmitPass(RegExpCompiler *compiler, TextEmitPassType pass, bool preloaded, Trace *trace, bool first_element_checked, int *checked_up_to)
ZoneList< TextElement > * elements()
ActionNode::ActionType action_type()
void set_stop_node(RegExpNode *node)
int characters_preloaded()
void Flush(RegExpCompiler *compiler, RegExpNode *successor)
int FindAffectedRegisters(OutSet *affected_registers, Zone *zone)
int bound_checked_up_to()
int characters_preloaded_
DeferredAction * actions_
void RestoreAffectedRegisters(RegExpMacroAssembler *macro, int max_register, const OutSet ®isters_to_pop, const OutSet ®isters_to_clear)
DeferredAction * actions()
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler *compiler)
void set_characters_preloaded(int count)
void add_action(DeferredAction *new_action)
void set_at_start(bool at_start)
void set_quick_check_performed(QuickCheckDetails *d)
void PerformDeferredActions(RegExpMacroAssembler *macro, int max_register, const OutSet &affected_registers, OutSet *registers_to_pop, OutSet *registers_to_clear, Zone *zone)
bool mentions_reg(int reg)
bool GetStoredPosition(int reg, int *cp_offset)
void set_backtrack(Label *backtrack)
void set_bound_checked_up_to(int to)
QuickCheckDetails quick_check_performed_
void set_loop_label(Label *label)
void set_flush_budget(int to)
void InvalidateCurrentCharacter()
QuickCheckDetails * quick_check_performed()
VisitMarker(NodeInfo *info)
Isolate * isolate() const
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes to(mksnapshot only)") DEFINE_STRING(raw_context_file
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call, T)
#define THROW_NEW_ERROR(isolate, call, T)
#define DEFINE_ACCEPT(Type)
#define FOR_EACH_NODE_TYPE(VISIT)
#define LOG(isolate, Call)
#define DCHECK_LE(v1, v2)
#define DCHECK_NOT_NULL(p)
#define DCHECK_RESULT(expr)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
Vector< const char > CStrVector(const char *data)
int SearchString(Isolate *isolate, Vector< const SubjectChar > subject, Vector< const PatternChar > pattern, int start_index)
const int kPatternTooShortForBoyerMoore
static const int kLineTerminatorRanges[]
static bool CompareInverseRanges(ZoneList< CharacterRange > *ranges, const int *special_class, int length)
static const int kSurrogateRanges[]
static void MoveRanges(ZoneList< CharacterRange > *list, int from, int to, int count)
static void EmitCharClass(RegExpMacroAssembler *macro_assembler, RegExpCharacterClass *cc, bool one_byte, Label *on_failure, int cp_offset, bool check_offset, bool preloaded, Zone *zone)
static void EmitDoubleBoundaryTest(RegExpMacroAssembler *masm, int first, int last, Label *fall_through, Label *in_range, Label *out_of_range)
static int min(int a, int b)
static LifetimePosition Min(LifetimePosition a, LifetimePosition b)
static int InsertRangeInCanonicalList(ZoneList< CharacterRange > *list, int count, CharacterRange insert)
static void EmitUseLookupTable(RegExpMacroAssembler *masm, ZoneList< int > *ranges, int start_index, int end_index, int min_char, Label *fall_through, Label *even_label, Label *odd_label)
static int GetCaseIndependentLetters(Isolate *isolate, uc16 character, bool one_byte_subject, unibrow::uchar *letters)
static const int kWordRanges[]
static const int kLineTerminatorRangeCount
ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b)
static bool EmitAtomLetter(Isolate *isolate, RegExpCompiler *compiler, uc16 c, Label *on_failure, int cp_offset, bool check, bool preloaded)
static bool DeterminedAlready(QuickCheckDetails *quick_check, int offset)
static void GenerateBranches(RegExpMacroAssembler *masm, ZoneList< int > *ranges, int start_index, int end_index, uc16 min_char, uc16 max_char, Label *fall_through, Label *even_label, Label *odd_label)
OStream & endl(OStream &os)
static uint32_t SmearBitsRight(uint32_t v)
static void SplitSearchSpace(ZoneList< int > *ranges, int start_index, int end_index, int *new_start_index, int *new_end_index, int *border)
static void CreateRegExpErrorObjectAndThrow(Handle< JSRegExp > re, Handle< String > error_message, Isolate *isolate)
static void EmitBoundaryTest(RegExpMacroAssembler *masm, int border, Label *fall_through, Label *above_or_equal, Label *below)
static bool HasFewDifferentCharacters(Handle< String > pattern)
static void EmitWordCheck(RegExpMacroAssembler *assembler, Label *word, Label *non_word, bool fall_through_on_word)
static const int kSpaceRanges[]
static void UpdateBoundsCheck(int index, int *checked_up_to)
static LifetimePosition Max(LifetimePosition a, LifetimePosition b)
static bool EmitAtomNonLetter(Isolate *isolate, RegExpCompiler *compiler, uc16 c, Label *on_failure, int cp_offset, bool check, bool preloaded)
static bool RangesContainLatin1Equivalents(ZoneList< CharacterRange > *ranges)
static const int kSpaceRangeCount
void PrintF(const char *format,...)
const int kMaxLookaheadForBoyerMoore
static bool RangeContainsLatin1Equivalents(CharacterRange range)
static void AddClassNegated(const int *elmv, int elmc, ZoneList< CharacterRange > *ranges, Zone *zone)
static int CompareRangeByFrom(const CharacterRange *a, const CharacterRange *b)
static RegExpEngine::CompilationResult IrregexpRegExpTooBig(Isolate *isolate)
static bool EmitSimpleCharacter(Isolate *isolate, RegExpCompiler *compiler, uc16 c, Label *on_failure, int cp_offset, bool check, bool preloaded)
bool EmitCharacterFunction(Isolate *isolate, RegExpCompiler *compiler, uc16 c, Label *on_failure, int cp_offset, bool check, bool preloaded)
unibrow::Mapping< unibrow::Ecma262Canonicalize > Canonicalize
static const int kDigitRanges[]
static const int kWordRangeCount
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
static JSRegExp::Flags RegExpFlagsFromString(Handle< String > str)
static void CutOutRange(RegExpMacroAssembler *masm, ZoneList< int > *ranges, int start_index, int end_index, int cut_index, Label *even_label, Label *odd_label)
static MUST_USE_RESULT MaybeHandle< Object > ThrowRegExpException(Handle< JSRegExp > re, Handle< String > pattern, Handle< String > error_text, const char *message)
static const int kSurrogateRangeCount
static bool CompareRanges(ZoneList< CharacterRange > *ranges, const int *special_class, int length)
static void EmitHat(RegExpCompiler *compiler, RegExpNode *on_success, Trace *trace)
static const int kDigitRangeCount
void MemCopy(void *dest, const void *src, size_t size)
static bool ShortCutEmitCharacterPair(RegExpMacroAssembler *macro_assembler, bool one_byte, uc16 c1, uc16 c2, Label *on_failure)
static void AddClass(const int *elmv, int elmc, ZoneList< CharacterRange > *ranges, Zone *zone)
static void SetAtomLastCapture(FixedArray *array, String *subject, int from, int to)
ContainedInLattice AddRange(ContainedInLattice containment, const int *ranges, int ranges_length, Interval new_range)
Debugger support for the V8 JavaScript engine.
static const int kMaxWidth
void AddFromFollowing(NodeInfo *that)
static const int kEatsAtLeastNotYetInitialized
bool preload_has_checked_bounds_
bool determines_perfectly
const char * error_message