47 #ifndef V8_INTERPRETED_REGEXP
48 #if V8_TARGET_ARCH_IA32
50 #elif V8_TARGET_ARCH_X64
52 #elif V8_TARGET_ARCH_ARM64
54 #elif V8_TARGET_ARCH_ARM
56 #elif V8_TARGET_ARCH_MIPS
59 #error Unsupported target architecture.
72 bool* has_pending_exception) {
76 has_pending_exception);
82 for (
int i = 0; i < str->length(); i++) {
83 switch (str->Get(i)) {
95 return JSRegExp::Flags(flags);
99 static inline void ThrowRegExpException(Handle<JSRegExp> re,
100 Handle<String> pattern,
101 Handle<String> error_text,
103 Isolate* isolate = re->GetIsolate();
104 Factory* factory = isolate->factory();
105 Handle<FixedArray> elements = factory->NewFixedArray(2);
106 elements->set(0, *pattern);
107 elements->set(1, *error_text);
108 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
109 Handle<Object> regexp_err = factory->NewSyntaxError(message, array);
110 isolate->Throw(*regexp_err);
118 ASSERT((ranges_length & 1) == 1);
123 for (
int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) {
126 if (ranges[i] <= new_range.
from())
continue;
129 if (last <= new_range.
from() && new_range.
to() < ranges[i]) {
150 const int kMod = 128;
151 bool character_found[kMod];
153 memset(&character_found[0], 0,
sizeof(character_found));
154 for (
int i = 0; i < length; i++) {
155 int ch = (pattern->Get(i) & (kMod - 1));
156 if (!character_found[ch]) {
157 character_found[ch] =
true;
161 if (different * 3 > length)
return false;
174 Isolate* isolate = re->GetIsolate();
179 bool in_cache = !cached.
is_null();
180 LOG(isolate, RegExpCompileEvent(re, in_cache));
184 re->set_data(*cached);
188 PostponeInterruptsScope postpone(isolate);
191 if (!RegExpParser::ParseRegExp(&reader, flags.
is_multiline(),
192 &parse_result, &zone)) {
194 ThrowRegExpException(re,
201 bool has_been_compiled =
false;
203 if (parse_result.
simple &&
205 !HasFewDifferentCharacters(pattern)) {
208 has_been_compiled =
true;
209 }
else if (parse_result.
tree->IsAtom() &&
212 RegExpAtom* atom = parse_result.
tree->AsAtom();
216 if (!HasFewDifferentCharacters(atom_string)) {
218 has_been_compiled =
true;
221 if (!has_been_compiled) {
224 ASSERT(re->data()->IsFixedArray());
228 compilation_cache->
PutRegExp(pattern, flags, data);
238 switch (regexp->TypeTag()) {
240 return AtomExec(regexp, subject, index, last_match_info);
244 ASSERT(!result.is_null() ||
245 regexp->GetIsolate()->has_pending_exception());
262 re->GetIsolate()->factory()->SetRegExpAtomData(re,
270 static void SetAtomLastCapture(
FixedArray* array,
288 Isolate* isolate = regexp->GetIsolate();
291 ASSERT(index <= subject->length());
297 int needle_len = needle->
length();
301 if (index + needle_len > subject->length()) {
305 for (
int i = 0; i < output_size; i += 2) {
311 index = (needle_content.
IsAscii()
334 output[i+1] = index + needle_len;
338 return output_size / 2;
346 Isolate* isolate = re->GetIsolate();
350 int32_t* output_registers = isolate->jsregexp_static_offsets_vector();
352 int res =
AtomExecRaw(re, subject, index, output_registers, kNumRegisters);
357 SealHandleScope shs(isolate);
359 SetAtomLastCapture(array, *subject, output_registers[0], output_registers[1]);
360 return last_match_info;
372 bool RegExpImpl::EnsureCompiledIrregexp(
375 #ifdef V8_INTERPRETED_REGEXP
376 if (compiled_code->IsByteArray())
return true;
377 #else // V8_INTERPRETED_REGEXP (RegExp native code)
378 if (compiled_code->IsCode())
return true;
383 if (saved_code->IsCode()) {
386 ASSERT(compiled_code->IsSmi());
389 return CompileIrregexp(re, sample_subject, is_ascii);
393 static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re,
395 Handle<String> error_message,
397 Factory* factory = isolate->factory();
398 Handle<FixedArray> elements = factory->NewFixedArray(2);
399 elements->set(0, re->Pattern());
400 elements->set(1, *error_message);
401 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
402 Handle<Object> regexp_err =
403 factory->NewSyntaxError(
"malformed_regexp", array);
404 isolate->Throw(*regexp_err);
409 bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re,
410 Handle<String> sample_subject,
415 PostponeInterruptsScope postpone(isolate);
426 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0));
433 ASSERT(error_string->IsString());
434 Handle<String> error_message(
String::cast(error_string));
435 CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
439 JSRegExp::Flags flags = re->GetFlags();
441 Handle<String> pattern(re->Pattern());
443 RegExpCompileData compile_data;
444 FlatStringReader reader(isolate, pattern);
445 if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(),
450 ThrowRegExpException(re,
456 RegExpEngine::CompilationResult result =
458 flags.is_ignore_case(),
460 flags.is_multiline(),
465 if (result.error_message !=
NULL) {
467 Handle<String> error_message =
468 isolate->factory()->NewStringFromUtf8(
CStrVector(result.error_message));
469 ASSERT(!error_message.is_null());
470 CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
477 if (result.num_registers > register_max) {
521 re->GetIsolate()->factory()->SetRegExpIrregexpData(re,
534 bool is_ascii = subject->IsOneByteRepresentationUnderneath();
535 if (!EnsureCompiledIrregexp(regexp, subject, is_ascii))
return -1;
537 #ifdef V8_INTERPRETED_REGEXP
544 #else // V8_INTERPRETED_REGEXP
548 #endif // V8_INTERPRETED_REGEXP
557 Isolate* isolate = regexp->GetIsolate();
562 ASSERT(index <= subject->length());
563 ASSERT(subject->IsFlat());
565 bool is_ascii = subject->IsOneByteRepresentationUnderneath();
567 #ifndef V8_INTERPRETED_REGEXP
570 EnsureCompiledIrregexp(regexp, subject, is_ascii);
601 is_ascii = subject->IsOneByteRepresentationUnderneath();
605 #else // V8_INTERPRETED_REGEXP
610 int number_of_capture_registers =
612 int32_t* raw_output = &output[number_of_capture_registers];
616 for (
int i = number_of_capture_registers - 1; i >= 0; i--) {
629 output, raw_output, number_of_capture_registers *
sizeof(
int32_t));
636 #endif // V8_INTERPRETED_REGEXP
644 Isolate* isolate = regexp->GetIsolate();
648 #if defined(V8_INTERPRETED_REGEXP) && defined(DEBUG)
649 if (FLAG_trace_regexp_bytecodes) {
650 String* pattern = regexp->Pattern();
652 PrintF(
"\n\nSubject string: '%s'\n\n", subject->ToCString().get());
656 if (required_registers < 0) {
664 output_registers = NewArray<int32_t>(required_registers);
667 if (output_registers ==
NULL) {
668 output_registers = isolate->jsregexp_static_offsets_vector();
672 regexp, subject, previous_index, output_registers, required_registers);
677 last_match_info, subject, capture_count, output_registers);
684 return isolate->
factory()->null_value();
692 ASSERT(last_match_info->HasFastObjectElements());
693 int capture_register_count = (capture_count + 1) * 2;
699 for (
int i = 0; i < capture_register_count; i += 2) {
707 return last_match_info;
715 : register_array_(
NULL),
716 register_array_size_(0),
719 #ifdef V8_INTERPRETED_REGEXP
720 bool interpreted =
true;
722 bool interpreted =
false;
723 #endif // V8_INTERPRETED_REGEXP
726 static const int kAtomRegistersPerMatch = 2;
727 registers_per_match_ = kAtomRegistersPerMatch;
732 if (registers_per_match_ < 0) {
738 if (is_global && !interpreted) {
739 register_array_size_ =
741 max_matches_ = register_array_size_ / registers_per_match_;
745 register_array_size_ = registers_per_match_;
750 register_array_ = NewArray<int32_t>(register_array_size_);
752 register_array_ = isolate->jsregexp_static_offsets_vector();
757 current_match_index_ = max_matches_ - 1;
758 num_matches_ = max_matches_;
759 ASSERT(registers_per_match_ >= 2);
760 ASSERT_GE(register_array_size_, registers_per_match_);
762 ®ister_array_[current_match_index_ * registers_per_match_];
923 void RegExpAtom::AppendToText(RegExpText* text,
Zone* zone) {
924 text->AddElement(TextElement::Atom(
this), zone);
928 void RegExpCharacterClass::AppendToText(RegExpText* text, Zone* zone) {
929 text->AddElement(TextElement::CharClass(
this), zone);
933 void RegExpText::AppendToText(RegExpText* text, Zone* zone) {
934 for (
int i = 0; i < elements()->length(); i++)
935 text->AddElement(elements()->at(i), zone);
939 TextElement TextElement::Atom(RegExpAtom* atom) {
940 return TextElement(ATOM, atom);
944 TextElement TextElement::CharClass(RegExpCharacterClass* char_class) {
945 return TextElement(CHAR_CLASS, char_class);
949 int TextElement::length()
const {
950 switch (text_type()) {
952 return atom()->length();
963 if (table_ ==
NULL) {
976 frequencies_[i] = CharacterFrequency(i);
982 frequencies_[index].Increment();
990 if (total_samples_ < 1)
return 1;
992 (frequencies_[in_character].counter() * 128) / total_samples_;
993 return freq_in_per128;
997 class CharacterFrequency {
999 CharacterFrequency() : counter_(0), character_(-1) { }
1000 explicit CharacterFrequency(
int character)
1001 : counter_(0), character_(character) { }
1003 void Increment() { counter_++; }
1004 int counter() {
return counter_; }
1005 int character() {
return character_; }
1021 RegExpCompiler(
int capture_count,
bool ignore_case,
bool is_ascii,
1026 reg_exp_too_big_ =
true;
1027 return next_register_;
1029 return next_register_++;
1039 static const int kImplementationOffset = 0;
1040 static const int kNumberOfRegistersOffset = 0;
1041 static const int kCodeOffset = 1;
1046 static const int kMaxRecursion = 100;
1059 current_expansion_factor_ = value;
1070 int recursion_depth_;
1074 bool reg_exp_too_big_;
1075 int current_expansion_factor_;
1092 static RegExpEngine::CompilationResult IrregexpRegExpTooBig(
Isolate* isolate) {
1093 return RegExpEngine::CompilationResult(isolate,
"RegExp too big");
1101 : next_register_(2 * (capture_count + 1)),
1103 recursion_depth_(0),
1104 ignore_case_(ignore_case),
1106 reg_exp_too_big_(
false),
1107 current_expansion_factor_(1),
1108 frequency_collator_(),
1120 Heap* heap = pattern->GetHeap();
1122 bool use_slow_safe_regexp_compiler =
false;
1127 use_slow_safe_regexp_compiler =
true;
1130 macro_assembler->
set_slow_safe(use_slow_safe_regexp_compiler);
1133 if (FLAG_trace_regexp_assembler)
1140 work_list_ = &work_list;
1144 start->
Emit(
this, &new_trace);
1145 macro_assembler_->
Bind(&fail);
1146 macro_assembler_->
Fail();
1147 while (!work_list.is_empty()) {
1148 work_list.RemoveLast()->Emit(
this, &new_trace);
1150 if (reg_exp_too_big_)
return IrregexpRegExpTooBig(zone_->
isolate());
1156 if (FLAG_print_code) {
1159 trace_scope.file());
1161 if (FLAG_trace_regexp_assembler) {
1162 delete macro_assembler_;
1174 return reg() == that;
1182 action = action->next()) {
1183 if (action->Mentions(reg))
1194 action = action->next()) {
1195 if (action->Mentions(reg)) {
1208 int Trace::FindAffectedRegisters(
OutSet* affected_registers,
1211 for (DeferredAction* action = actions_;
1213 action = action->next()) {
1215 Interval range =
static_cast<DeferredClearCaptures*
>(action)->range();
1216 for (
int i = range.
from(); i <= range.
to(); i++)
1217 affected_registers->Set(i, zone);
1218 if (range.
to() > max_register) max_register = range.
to();
1220 affected_registers->Set(action->reg(), zone);
1221 if (action->reg() > max_register) max_register = action->reg();
1224 return max_register;
1228 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler,
1230 OutSet& registers_to_pop,
1231 OutSet& registers_to_clear) {
1232 for (
int reg = max_register; reg >= 0; reg--) {
1233 if (registers_to_pop.Get(reg)) assembler->PopRegister(reg);
1234 else if (registers_to_clear.Get(reg)) {
1236 while (reg > 0 && registers_to_clear.Get(reg - 1)) {
1239 assembler->ClearRegisters(reg, clear_to);
1245 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
1247 OutSet& affected_registers,
1248 OutSet* registers_to_pop,
1249 OutSet* registers_to_clear,
1252 const int push_limit = (assembler->stack_limit_slack() + 1) / 2;
1257 for (
int reg = 0; reg <= max_register; reg++) {
1258 if (!affected_registers.Get(reg)) {
1265 enum DeferredActionUndoType { IGNORE, RESTORE, CLEAR };
1266 DeferredActionUndoType undo_action = IGNORE;
1269 bool absolute =
false;
1271 int store_position = -1;
1274 for (DeferredAction* action = actions_;
1276 action = action->next()) {
1277 if (action->Mentions(reg)) {
1278 switch (action->action_type()) {
1280 Trace::DeferredSetRegister* psr =
1281 static_cast<Trace::DeferredSetRegister*
>(action);
1283 value += psr->value();
1291 undo_action = RESTORE;
1302 undo_action = RESTORE;
1305 Trace::DeferredCapture*
pc =
1306 static_cast<Trace::DeferredCapture*
>(action);
1307 if (!clear && store_position == -1) {
1308 store_position = pc->cp_offset();
1319 undo_action = IGNORE;
1321 undo_action = pc->is_capture() ? CLEAR : RESTORE;
1331 if (store_position == -1) {
1334 undo_action = RESTORE;
1346 if (undo_action == RESTORE) {
1350 if (pushes == push_limit) {
1355 assembler->PushRegister(reg, stack_check);
1356 registers_to_pop->Set(reg, zone);
1357 }
else if (undo_action == CLEAR) {
1358 registers_to_clear->Set(reg, zone);
1362 if (store_position != -1) {
1363 assembler->WriteCurrentPositionToRegister(reg, store_position);
1365 assembler->ClearRegisters(reg, reg);
1366 }
else if (absolute) {
1367 assembler->SetRegister(reg, value);
1368 }
else if (value != 0) {
1369 assembler->AdvanceRegister(reg, value);
1390 successor->
Emit(compiler, &new_state);
1395 OutSet affected_registers;
1404 int max_register = FindAffectedRegisters(&affected_registers,
1407 OutSet registers_to_clear;
1408 PerformDeferredActions(assembler,
1412 ®isters_to_clear,
1414 if (cp_offset_ != 0) {
1422 successor->
Emit(compiler, &new_state);
1425 assembler->
Bind(&undo);
1426 RestoreAffectedRegisters(assembler,
1429 registers_to_clear);
1444 if (!label()->is_bound()) {
1447 assembler->
Bind(label());
1454 if (clear_capture_count_ > 0) {
1457 int clear_capture_end = clear_capture_start_ + clear_capture_count_ - 1;
1458 assembler->
ClearRegisters(clear_capture_start_, clear_capture_end);
1468 trace->
Flush(compiler,
this);
1472 if (!label()->is_bound()) {
1473 assembler->
Bind(label());
1482 case NEGATIVE_SUBMATCH_SUCCESS:
1491 if (guards_ ==
NULL)
1493 guards_->
Add(guard, zone);
1510 new(on_success->
zone())
ActionNode(INCREMENT_REGISTER, on_success);
1542 result->data_.
u_submatch.stack_pointer_register = stack_reg;
1543 result->data_.
u_submatch.current_position_register = position_reg;
1550 int clear_register_count,
1551 int clear_register_from,
1554 new(on_success->
zone())
ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success);
1555 result->data_.
u_submatch.stack_pointer_register = stack_reg;
1556 result->data_.
u_submatch.current_position_register = position_reg;
1557 result->data_.
u_submatch.clear_register_count = clear_register_count;
1558 result->data_.
u_submatch.clear_register_from = clear_register_from;
1564 int repetition_register,
1565 int repetition_limit,
1568 new(on_success->
zone())
ActionNode(EMPTY_MATCH_CHECK, on_success);
1576 #define DEFINE_ACCEPT(Type) \
1577 void Type##Node::Accept(NodeVisitor* visitor) { \
1578 visitor->Visit##Type(this); \
1581 #undef DEFINE_ACCEPT
1596 switch (guard->
op()) {
1615 static int GetCaseIndependentLetters(Isolate* isolate,
1620 isolate->jsregexp_uncanonicalize()->get(character,
'\0', letters);
1624 letters[0] = character;
1636 static inline bool EmitSimpleCharacter(Isolate* isolate,
1637 RegExpCompiler* compiler,
1643 RegExpMacroAssembler* assembler = compiler->macro_assembler();
1644 bool bound_checked =
false;
1646 assembler->LoadCurrentCharacter(
1650 bound_checked =
true;
1652 assembler->CheckNotCharacter(c, on_failure);
1653 return bound_checked;
1659 static inline bool EmitAtomNonLetter(Isolate* isolate,
1660 RegExpCompiler* compiler,
1666 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
1667 bool ascii = compiler->ascii();
1669 int length = GetCaseIndependentLetters(isolate, c, ascii, chars);
1675 bool checked =
false;
1683 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check);
1686 macro_assembler->CheckNotCharacter(c, on_failure);
1692 static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler,
1696 Label* on_failure) {
1703 uc16 exor = c1 ^ c2;
1705 if (((exor - 1) & exor) == 0) {
1709 uc16 mask = char_mask ^ exor;
1710 macro_assembler->CheckNotCharacterAfterAnd(c1, mask, on_failure);
1714 uc16 diff = c2 - c1;
1715 if (((diff - 1) & diff) == 0 && c1 >= diff) {
1720 uc16 mask = char_mask ^ diff;
1721 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff,
1741 static inline bool EmitAtomLetter(
Isolate* isolate,
1749 bool ascii = compiler->
ascii();
1751 int length = GetCaseIndependentLetters(isolate, c, ascii, chars);
1752 if (length <= 1)
return false;
1762 if (ShortCutEmitCharacterPair(macro_assembler,
1770 macro_assembler->
Bind(&ok);
1781 macro_assembler->
Bind(&ok);
1791 static void EmitBoundaryTest(RegExpMacroAssembler* masm,
1793 Label* fall_through,
1794 Label* above_or_equal,
1796 if (below != fall_through) {
1797 masm->CheckCharacterLT(border, below);
1798 if (above_or_equal != fall_through) masm->GoTo(above_or_equal);
1800 masm->CheckCharacterGT(border - 1, above_or_equal);
1805 static void EmitDoubleBoundaryTest(RegExpMacroAssembler* masm,
1808 Label* fall_through,
1810 Label* out_of_range) {
1811 if (in_range == fall_through) {
1812 if (first == last) {
1813 masm->CheckNotCharacter(first, out_of_range);
1815 masm->CheckCharacterNotInRange(first, last, out_of_range);
1818 if (first == last) {
1819 masm->CheckCharacter(first, in_range);
1821 masm->CheckCharacterInRange(first, last, in_range);
1823 if (out_of_range != fall_through) masm->GoTo(out_of_range);
1830 static void EmitUseLookupTable(
1831 RegExpMacroAssembler* masm,
1832 ZoneList<int>* ranges,
1836 Label* fall_through,
1842 int base = (min_char & ~kMask);
1846 for (
int i = start_index; i <= end_index; i++) {
1847 ASSERT_EQ(ranges->at(i) & ~kMask, base);
1849 ASSERT(start_index == 0 || (ranges->at(start_index - 1) & ~kMask) <= base);
1853 Label* on_bit_clear;
1855 if (even_label == fall_through) {
1856 on_bit_set = odd_label;
1857 on_bit_clear = even_label;
1860 on_bit_set = even_label;
1861 on_bit_clear = odd_label;
1864 for (
int i = 0; i < (ranges->at(start_index) & kMask) && i < kSize; i++) {
1869 for (
int i = start_index; i < end_index; i++) {
1870 for (j = (ranges->at(i) & kMask); j < (ranges->at(i + 1) & kMask); j++) {
1875 for (
int i = j; i < kSize; i++) {
1878 Factory* factory = masm->zone()->isolate()->factory();
1880 Handle<ByteArray> ba = factory->NewByteArray(kSize,
TENURED);
1881 for (
int i = 0; i < kSize; i++) {
1882 ba->set(i, templ[i]);
1884 masm->CheckBitInTable(ba, on_bit_set);
1885 if (on_bit_clear != fall_through) masm->GoTo(on_bit_clear);
1889 static void CutOutRange(RegExpMacroAssembler* masm,
1890 ZoneList<int>* ranges,
1896 bool odd = (((cut_index - start_index) & 1) == 1);
1897 Label* in_range_label = odd ? odd_label : even_label;
1899 EmitDoubleBoundaryTest(masm,
1900 ranges->at(cut_index),
1901 ranges->at(cut_index + 1) - 1,
1905 ASSERT(!dummy.is_linked());
1909 for (
int j = cut_index; j > start_index; j--) {
1910 ranges->at(j) = ranges->at(j - 1);
1912 for (
int j = cut_index + 1; j < end_index; j++) {
1913 ranges->at(j) = ranges->at(j + 1);
1920 static void SplitSearchSpace(ZoneList<int>* ranges,
1923 int* new_start_index,
1929 int first = ranges->at(start_index);
1930 int last = ranges->at(end_index) - 1;
1932 *new_start_index = start_index;
1933 *border = (ranges->at(start_index) & ~kMask) + kSize;
1934 while (*new_start_index < end_index) {
1935 if (ranges->at(*new_start_index) > *border)
break;
1936 (*new_start_index)++;
1949 int binary_chop_index = (end_index + start_index) / 2;
1955 end_index - start_index > (*new_start_index - start_index) * 2 &&
1956 last - first > kSize * 2 &&
1957 binary_chop_index > *new_start_index &&
1958 ranges->at(binary_chop_index) >= first + 2 * kSize) {
1959 int scan_forward_for_section_border = binary_chop_index;;
1960 int new_border = (ranges->at(binary_chop_index) | kMask) + 1;
1962 while (scan_forward_for_section_border < end_index) {
1963 if (ranges->at(scan_forward_for_section_border) > new_border) {
1964 *new_start_index = scan_forward_for_section_border;
1965 *border = new_border;
1968 scan_forward_for_section_border++;
1972 ASSERT(*new_start_index > start_index);
1973 *new_end_index = *new_start_index - 1;
1974 if (ranges->at(*new_end_index) == *border) {
1977 if (*border >= ranges->at(end_index)) {
1978 *border = ranges->at(end_index);
1979 *new_start_index = end_index;
1980 *new_end_index = end_index - 1;
1991 static void GenerateBranches(RegExpMacroAssembler* masm,
1992 ZoneList<int>* ranges,
1997 Label* fall_through,
2000 int first = ranges->at(start_index);
2001 int last = ranges->at(end_index) - 1;
2007 if (start_index == end_index) {
2008 EmitBoundaryTest(masm, first, fall_through, even_label, odd_label);
2014 if (start_index + 1 == end_index) {
2015 EmitDoubleBoundaryTest(
2016 masm, first, last, fall_through, even_label, odd_label);
2022 if (end_index - start_index <= 6) {
2025 static int kNoCutIndex = -1;
2026 int cut = kNoCutIndex;
2027 for (
int i = start_index; i < end_index; i++) {
2028 if (ranges->at(i) == ranges->at(i + 1) - 1) {
2033 if (cut == kNoCutIndex) cut = start_index;
2035 masm, ranges, start_index, end_index, cut, even_label, odd_label);
2037 GenerateBranches(masm,
2053 if ((max_char >> kBits) == (min_char >> kBits)) {
2054 EmitUseLookupTable(masm,
2065 if ((min_char >> kBits) != (first >> kBits)) {
2066 masm->CheckCharacterLT(first, odd_label);
2067 GenerateBranches(masm,
2079 int new_start_index = 0;
2080 int new_end_index = 0;
2083 SplitSearchSpace(ranges,
2091 Label*
above = &handle_rest;
2092 if (border == last + 1) {
2095 above = (end_index & 1) != (start_index & 1) ? odd_label : even_label;
2096 ASSERT(new_end_index == end_index - 1);
2101 ASSERT_LT(start_index, new_start_index);
2103 ASSERT(new_end_index + 1 == new_start_index ||
2104 (new_end_index + 2 == new_start_index &&
2105 border == ranges->at(new_end_index + 1)));
2108 ASSERT_LT(ranges->at(new_end_index), border);
2109 ASSERT(border < ranges->at(new_start_index) ||
2110 (border == ranges->at(new_start_index) &&
2111 new_start_index == end_index &&
2112 new_end_index == end_index - 1 &&
2113 border == last + 1));
2114 ASSERT(new_start_index == 0 || border >= ranges->at(new_start_index - 1));
2116 masm->CheckCharacterGT(border - 1, above);
2118 GenerateBranches(masm,
2127 if (handle_rest.is_linked()) {
2128 masm->Bind(&handle_rest);
2129 bool flip = (new_start_index & 1) != (start_index & 1);
2130 GenerateBranches(masm,
2137 flip ? odd_label : even_label,
2138 flip ? even_label : odd_label);
2143 static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
2144 RegExpCharacterClass*
cc,
2151 ZoneList<CharacterRange>* ranges = cc->ranges(zone);
2163 int range_count = ranges->length();
2165 int last_valid_range = range_count - 1;
2166 while (last_valid_range >= 0) {
2167 CharacterRange& range = ranges->at(last_valid_range);
2168 if (range.from() <= max_char) {
2174 if (last_valid_range < 0) {
2175 if (!cc->is_negated()) {
2176 macro_assembler->GoTo(on_failure);
2179 macro_assembler->CheckPosition(cp_offset, on_failure);
2184 if (last_valid_range == 0 &&
2185 ranges->at(0).IsEverything(max_char)) {
2186 if (cc->is_negated()) {
2187 macro_assembler->GoTo(on_failure);
2191 macro_assembler->CheckPosition(cp_offset, on_failure);
2196 if (last_valid_range == 0 &&
2197 !cc->is_negated() &&
2198 ranges->at(0).IsEverything(max_char)) {
2201 macro_assembler->CheckPosition(cp_offset, on_failure);
2207 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check_offset);
2210 if (cc->is_standard(zone) &&
2211 macro_assembler->CheckSpecialCharacterClass(cc->standard_type(),
2223 ZoneList<int>* range_boundaries =
2224 new(zone) ZoneList<int>(last_valid_range, zone);
2226 bool zeroth_entry_is_failure = !cc->is_negated();
2228 for (
int i = 0; i <= last_valid_range; i++) {
2229 CharacterRange& range = ranges->at(i);
2230 if (range.from() == 0) {
2232 zeroth_entry_is_failure = !zeroth_entry_is_failure;
2234 range_boundaries->Add(range.from(), zone);
2236 range_boundaries->Add(range.to() + 1, zone);
2238 int end_index = range_boundaries->length() - 1;
2239 if (range_boundaries->at(end_index) > max_char) {
2244 GenerateBranches(macro_assembler,
2251 zeroth_entry_is_failure ? &fall_through : on_failure,
2252 zeroth_entry_is_failure ? on_failure : &fall_through);
2253 macro_assembler->Bind(&fall_through);
2270 if (label_.is_bound()) {
2273 macro_assembler->
GoTo(&label_);
2280 macro_assembler->
GoTo(&label_);
2284 macro_assembler->
Bind(&label_);
2291 if (FLAG_regexp_optimization &&
2292 trace_count_ < kMaxCopiesCodeGenerated &&
2300 trace->
Flush(compiler,
this);
2307 bool not_at_start) {
2308 if (budget <= 0)
return 0;
2309 if (action_type_ == POSITIVE_SUBMATCH_SUCCESS)
return 0;
2310 return on_success()->EatsAtLeast(still_to_find,
2319 bool not_at_start) {
2320 if (action_type_ == BEGIN_SUBMATCH) {
2322 }
else if (action_type_ != POSITIVE_SUBMATCH_SUCCESS) {
2323 on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
2325 SaveBMInfo(bm, not_at_start, offset);
2331 bool not_at_start) {
2332 if (budget <= 0)
return 0;
2338 if (assertion_type() == AT_START && not_at_start)
return still_to_find;
2339 return on_success()->EatsAtLeast(still_to_find,
2348 bool not_at_start) {
2350 if (assertion_type() == AT_START && not_at_start)
return;
2351 on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
2352 SaveBMInfo(bm, not_at_start, offset);
2358 bool not_at_start) {
2359 if (budget <= 0)
return 0;
2360 return on_success()->EatsAtLeast(still_to_find,
2368 bool not_at_start) {
2369 int answer = Length();
2370 if (answer >= still_to_find)
return answer;
2371 if (budget <= 0)
return answer;
2373 return answer + on_success()->EatsAtLeast(still_to_find - answer,
2381 bool not_at_start) {
2382 if (budget <= 0)
return 0;
2385 RegExpNode* node = alternatives_->at(1).node();
2386 return node->
EatsAtLeast(still_to_find, budget - 1, not_at_start);
2394 bool not_at_start) {
2397 RegExpNode* node = alternatives_->at(1).node();
2405 bool not_at_start) {
2406 if (budget <= 0)
return 0;
2408 int choice_count = alternatives_->length();
2409 budget = (budget - 1) / choice_count;
2410 for (
int i = 0; i < choice_count; i++) {
2411 RegExpNode* node = alternatives_->at(i).node();
2412 if (node == ignore_this_node)
continue;
2413 int node_eats_at_least =
2414 node->
EatsAtLeast(still_to_find, budget, not_at_start);
2415 if (node_eats_at_least < min) min = node_eats_at_least;
2416 if (min == 0)
return 0;
2424 bool not_at_start) {
2425 return EatsAtLeastHelper(still_to_find,
2434 bool not_at_start) {
2435 return EatsAtLeastHelper(still_to_find,
2443 static inline uint32_t SmearBitsRight(uint32_t v) {
2454 bool found_useful_op =
false;
2464 for (
int i = 0; i < characters_; i++) {
2467 found_useful_op =
true;
2469 mask_ |= (pos->
mask & char_mask) << char_shift;
2470 value_ |= (pos->
value & char_mask) << char_shift;
2471 char_shift += asc ? 8 : 16;
2473 return found_useful_op;
2479 bool preload_has_checked_bounds,
2480 Label* on_possible_success,
2482 bool fall_through_on_failure) {
2483 if (details->
characters() == 0)
return false;
2484 GetQuickCheckDetails(
2490 uint32_t mask = details->
mask();
2491 uint32_t value = details->
value();
2498 !preload_has_checked_bounds,
2503 bool need_mask =
true;
2509 if (compiler->
ascii()) {
2514 if ((mask & char_mask) == char_mask) need_mask =
false;
2520 if ((mask & 0xffff) == 0xffff) need_mask =
false;
2522 if ((mask & 0xffff) == 0xffff) need_mask =
false;
2524 if (mask == 0xffffffff) need_mask =
false;
2528 if (fall_through_on_failure) {
2555 int characters_filled_in,
2556 bool not_at_start) {
2558 ASSERT(characters_filled_in < details->characters());
2561 if (compiler->
ascii()) {
2566 for (
int k = 0; k < elms_->length(); k++) {
2567 TextElement elm = elms_->at(k);
2568 if (elm.text_type() == TextElement::ATOM) {
2570 for (
int i = 0; i < characters && i < quarks.
length(); i++) {
2572 details->
positions(characters_filled_in);
2574 if (c > char_mask) {
2585 int length = GetCaseIndependentLetters(isolate, c, compiler->
ascii(),
2592 pos->
mask = char_mask;
2596 uint32_t common_bits = char_mask;
2597 uint32_t bits = chars[0];
2598 for (
int j = 1; j < length; j++) {
2599 uint32_t differing_bits = ((chars[j] & common_bits) ^ bits);
2600 common_bits ^= differing_bits;
2601 bits &= common_bits;
2607 uint32_t one_zero = (common_bits | ~char_mask);
2608 if (length == 2 && ((~one_zero) & ((~one_zero) - 1)) == 0) {
2611 pos->
mask = common_bits;
2618 pos->
mask = char_mask;
2622 characters_filled_in++;
2623 ASSERT(characters_filled_in <= details->characters());
2624 if (characters_filled_in == details->
characters()) {
2630 details->
positions(characters_filled_in);
2631 RegExpCharacterClass* tree = elm.char_class();
2633 if (tree->is_negated()) {
2641 int first_range = 0;
2642 while (ranges->
at(first_range).from() > char_mask) {
2644 if (first_range == ranges->length()) {
2653 if (to > char_mask) {
2656 uint32_t differing_bits = (from ^ to);
2659 if ((differing_bits & (differing_bits + 1)) == 0 &&
2660 from + differing_bits == to) {
2663 uint32_t common_bits = ~SmearBitsRight(differing_bits);
2664 uint32_t bits = (from & common_bits);
2665 for (
int i = first_range + 1; i < ranges->length(); i++) {
2669 if (from > char_mask)
continue;
2670 if (to > char_mask) to = char_mask;
2677 uint32_t new_common_bits = (from ^ to);
2678 new_common_bits = ~SmearBitsRight(new_common_bits);
2679 common_bits &= new_common_bits;
2680 bits &= new_common_bits;
2681 uint32_t differing_bits = (from & common_bits) ^ bits;
2682 common_bits ^= differing_bits;
2683 bits &= common_bits;
2685 pos->
mask = common_bits;
2688 characters_filled_in++;
2689 ASSERT(characters_filled_in <= details->characters());
2690 if (characters_filled_in == details->
characters()) {
2697 on_success()-> GetQuickCheckDetails(details,
2699 characters_filled_in,
2706 for (
int i = 0; i < characters_; i++) {
2707 positions_[i].mask = 0;
2708 positions_[i].value = 0;
2709 positions_[i].determines_perfectly =
false;
2717 if (by >= characters_) {
2721 for (
int i = 0; i < characters_ - by; i++) {
2722 positions_[i] = positions_[by + i];
2724 for (
int i = characters_ - by; i < characters_; i++) {
2725 positions_[i].mask = 0;
2726 positions_[i].value = 0;
2727 positions_[i].determines_perfectly =
false;
2737 ASSERT(characters_ == other->characters_);
2738 if (other->cannot_match_) {
2741 if (cannot_match_) {
2745 for (
int i = from_index; i < characters_; i++) {
2748 if (pos->
mask != other_pos->
mask ||
2759 pos->
mask &= ~differing_bits;
2772 info_->visited =
false;
2780 if (
info()->replacement_calculated)
return replacement();
2781 if (depth < 0)
return this;
2784 return FilterSuccessor(depth - 1, ignore_case);
2790 if (next ==
NULL)
return set_replacement(
NULL);
2792 return set_replacement(
this);
2797 static inline bool RangeContainsLatin1Equivalents(
CharacterRange range) {
2804 static bool RangesContainLatin1Equivalents(ZoneList<CharacterRange>* ranges) {
2805 for (
int i = 0; i < ranges->length(); i++) {
2807 if (RangeContainsLatin1Equivalents(ranges->at(i)))
return true;
2814 if (
info()->replacement_calculated)
return replacement();
2815 if (depth < 0)
return this;
2818 int element_count = elms_->length();
2819 for (
int i = 0; i < element_count; i++) {
2820 TextElement elm = elms_->at(i);
2821 if (elm.text_type() == TextElement::ATOM) {
2823 for (
int j = 0; j < quarks.
length(); j++) {
2826 if (!ignore_case)
return set_replacement(
NULL);
2831 if (converted == 0)
return set_replacement(
NULL);
2834 copy[j] = converted;
2837 ASSERT(elm.text_type() == TextElement::CHAR_CLASS);
2838 RegExpCharacterClass* cc = elm.char_class();
2844 int range_count = ranges->length();
2845 if (cc->is_negated()) {
2846 if (range_count != 0 &&
2847 ranges->
at(0).from() == 0 &&
2850 if (ignore_case && RangesContainLatin1Equivalents(ranges))
continue;
2851 return set_replacement(
NULL);
2854 if (range_count == 0 ||
2857 if (ignore_case && RangesContainLatin1Equivalents(ranges))
continue;
2858 return set_replacement(
NULL);
2863 return FilterSuccessor(depth - 1, ignore_case);
2868 if (
info()->replacement_calculated)
return replacement();
2869 if (depth < 0)
return this;
2870 if (
info()->visited)
return this;
2875 continue_node_->
FilterASCII(depth - 1, ignore_case);
2878 if (continue_replacement ==
NULL)
return set_replacement(
NULL);
2886 if (
info()->replacement_calculated)
return replacement();
2887 if (depth < 0)
return this;
2888 if (
info()->visited)
return this;
2890 int choice_count = alternatives_->length();
2892 for (
int i = 0; i < choice_count; i++) {
2895 set_replacement(
this);
2902 for (
int i = 0; i < choice_count; i++) {
2906 ASSERT(replacement !=
this);
2907 if (replacement !=
NULL) {
2908 alternatives_->at(i).set_node(replacement);
2910 survivor = replacement;
2913 if (surviving < 2)
return set_replacement(survivor);
2915 set_replacement(
this);
2916 if (surviving == choice_count) {
2923 for (
int i = 0; i < choice_count; i++) {
2925 alternatives_->at(i).node()->
FilterASCII(depth - 1, ignore_case);
2926 if (replacement !=
NULL) {
2927 alternatives_->at(i).set_node(replacement);
2928 new_alternatives->
Add(alternatives_->at(i), zone());
2931 alternatives_ = new_alternatives;
2938 if (
info()->replacement_calculated)
return replacement();
2939 if (depth < 0)
return this;
2940 if (
info()->visited)
return this;
2944 RegExpNode* node = alternatives_->at(1).node();
2946 if (replacement ==
NULL)
return set_replacement(
NULL);
2947 alternatives_->at(1).set_node(replacement);
2949 RegExpNode* neg_node = alternatives_->at(0).node();
2953 if (neg_replacement ==
NULL)
return set_replacement(replacement);
2954 alternatives_->at(0).set_node(neg_replacement);
2955 return set_replacement(
this);
2961 int characters_filled_in,
2962 bool not_at_start) {
2963 if (body_can_be_zero_length_ ||
info()->visited)
return;
2967 characters_filled_in,
2975 bool not_at_start) {
2976 if (body_can_be_zero_length_ || budget <= 0) {
2978 SaveBMInfo(bm, not_at_start, offset);
2982 SaveBMInfo(bm, not_at_start, offset);
2988 int characters_filled_in,
2989 bool not_at_start) {
2990 not_at_start = (not_at_start || not_at_start_);
2991 int choice_count = alternatives_->length();
2992 ASSERT(choice_count > 0);
2993 alternatives_->at(0).node()->GetQuickCheckDetails(details,
2995 characters_filled_in,
2997 for (
int i = 1; i < choice_count; i++) {
2999 RegExpNode* node = alternatives_->at(i).node();
3001 characters_filled_in,
3004 details->
Merge(&new_details, characters_filled_in);
3013 bool fall_through_on_word) {
3015 fall_through_on_word ?
'w' :
'W',
3016 fall_through_on_word ? non_word : word)) {
3026 if (fall_through_on_word) {
3036 static void EmitHat(RegExpCompiler* compiler,
3037 RegExpNode* on_success,
3039 RegExpMacroAssembler* assembler = compiler->macro_assembler();
3042 Trace new_trace(*trace);
3043 new_trace.InvalidateCurrentCharacter();
3046 if (new_trace.cp_offset() == 0) {
3049 assembler->CheckAtStart(&ok);
3053 assembler->LoadCurrentCharacter(new_trace.cp_offset() -1,
3054 new_trace.backtrack(),
3056 if (!assembler->CheckSpecialCharacterClass(
'n',
3057 new_trace.backtrack())) {
3059 if (!compiler->ascii()) {
3060 assembler->CheckCharacterAfterAnd(0x2028, 0xfffe, &ok);
3062 assembler->CheckCharacter(
'\n', &ok);
3063 assembler->CheckNotCharacter(
'\r', new_trace.backtrack());
3065 assembler->Bind(&ok);
3066 on_success->Emit(compiler, &new_trace);
3071 void AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler,
Trace* trace) {
3072 RegExpMacroAssembler* assembler = compiler->macro_assembler();
3075 BoyerMooreLookahead* lookahead = bm_info(not_at_start);
3076 if (lookahead ==
NULL) {
3081 if (eats_at_least >= 1) {
3082 BoyerMooreLookahead* bm =
3083 new(zone()) BoyerMooreLookahead(eats_at_least, compiler, zone());
3084 FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
3085 if (bm->at(0)->is_non_word())
3090 if (lookahead->at(0)->is_non_word())
3092 if (lookahead->at(0)->is_word())
3097 Label before_non_word;
3099 if (trace->characters_preloaded() != 1) {
3100 assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
3103 EmitWordCheck(assembler, &before_word, &before_non_word,
false);
3105 assembler->Bind(&before_non_word);
3107 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
3108 assembler->GoTo(&ok);
3110 assembler->Bind(&before_word);
3111 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
3112 assembler->Bind(&ok);
3114 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
3117 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
3122 void AssertionNode::BacktrackIfPrevious(
3123 RegExpCompiler* compiler,
3125 AssertionNode::IfPrevious backtrack_if_previous) {
3126 RegExpMacroAssembler* assembler = compiler->macro_assembler();
3127 Trace new_trace(*trace);
3128 new_trace.InvalidateCurrentCharacter();
3130 Label fall_through, dummy;
3132 Label* non_word = backtrack_if_previous == kIsNonWord ?
3133 new_trace.backtrack() :
3135 Label* word = backtrack_if_previous == kIsNonWord ?
3137 new_trace.backtrack();
3139 if (new_trace.cp_offset() == 0) {
3142 assembler->CheckAtStart(non_word);
3146 assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy,
false);
3147 EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord);
3149 assembler->Bind(&fall_through);
3150 on_success()->Emit(compiler, &new_trace);
3157 bool not_at_start) {
3158 if (assertion_type_ == AT_START && not_at_start) {
3162 return on_success()->GetQuickCheckDetails(details,
3171 switch (assertion_type_) {
3176 assembler->
Bind(&ok);
3186 Trace at_start_trace = *trace;
3188 on_success()->Emit(compiler, &at_start_trace);
3194 EmitHat(compiler, on_success(), trace);
3197 case AT_NON_BOUNDARY: {
3198 EmitBoundaryCheck(compiler, trace);
3202 on_success()->Emit(compiler, trace);
3207 if (quick_check ==
NULL)
return false;
3208 if (offset >= quick_check->
characters())
return false;
3213 static void UpdateBoundsCheck(
int index,
int* checked_up_to) {
3214 if (index > *checked_up_to) {
3215 *checked_up_to = index;
3249 void TextNode::TextEmitPass(RegExpCompiler* compiler,
3250 TextEmitPassType pass,
3253 bool first_element_checked,
3254 int* checked_up_to) {
3255 RegExpMacroAssembler* assembler = compiler->macro_assembler();
3256 Isolate* isolate = assembler->zone()->isolate();
3257 bool ascii = compiler->ascii();
3259 QuickCheckDetails* quick_check = trace->quick_check_performed();
3260 int element_count = elms_->length();
3261 for (
int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
3262 TextElement elm = elms_->at(i);
3263 int cp_offset = trace->cp_offset() + elm.cp_offset();
3264 if (elm.text_type() == TextElement::ATOM) {
3265 Vector<const uc16> quarks = elm.atom()->data();
3266 for (
int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
3267 if (first_element_checked && i == 0 && j == 0)
continue;
3268 if (DeterminedAlready(quick_check, elm.cp_offset() + j))
continue;
3271 case NON_ASCII_MATCH:
3274 assembler->GoTo(backtrack);
3278 case NON_LETTER_CHARACTER_MATCH:
3279 emit_function = &EmitAtomNonLetter;
3281 case SIMPLE_CHARACTER_MATCH:
3282 emit_function = &EmitSimpleCharacter;
3284 case CASE_CHARACTER_MATCH:
3285 emit_function = &EmitAtomLetter;
3290 if (emit_function !=
NULL) {
3291 bool bound_checked = emit_function(isolate,
3296 *checked_up_to < cp_offset + j,
3298 if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to);
3302 ASSERT_EQ(TextElement::CHAR_CLASS, elm.text_type());
3303 if (pass == CHARACTER_CLASS_MATCH) {
3304 if (first_element_checked && i == 0)
continue;
3305 if (DeterminedAlready(quick_check, elm.cp_offset()))
continue;
3306 RegExpCharacterClass* cc = elm.char_class();
3307 EmitCharClass(assembler,
3312 *checked_up_to < cp_offset,
3315 UpdateBoundsCheck(cp_offset, checked_up_to);
3322 int TextNode::Length() {
3323 TextElement elm = elms_->last();
3324 ASSERT(elm.cp_offset() >= 0);
3325 return elm.cp_offset() + elm.length();
3329 bool TextNode::SkipPass(
int int_pass,
bool ignore_case) {
3330 TextEmitPassType pass =
static_cast<TextEmitPassType
>(int_pass);
3332 return pass == SIMPLE_CHARACTER_MATCH;
3334 return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH;
3346 LimitResult limit_result = LimitVersions(compiler, trace);
3347 if (limit_result ==
DONE)
return;
3348 ASSERT(limit_result == CONTINUE);
3355 if (compiler->
ascii()) {
3357 TextEmitPass(compiler, NON_ASCII_MATCH,
false, trace,
false, &dummy);
3360 bool first_elt_done =
false;
3361 int bound_checked_to = trace->
cp_offset() - 1;
3367 for (
int pass = kFirstRealPass; pass <= kLastPass; pass++) {
3369 TextEmitPass(compiler,
3370 static_cast<TextEmitPassType>(pass),
3377 first_elt_done =
true;
3380 for (
int pass = kFirstRealPass; pass <= kLastPass; pass++) {
3382 TextEmitPass(compiler,
3383 static_cast<TextEmitPassType>(pass),
3391 Trace successor_trace(*trace);
3395 on_success()->Emit(compiler, &successor_trace);
3400 characters_preloaded_ = 0;
3409 characters_preloaded_ = 0;
3419 bound_checked_up_to_ =
Max(0, bound_checked_up_to_ - by);
3424 int element_count = elms_->length();
3425 for (
int i = 0; i < element_count; i++) {
3426 TextElement elm = elms_->at(i);
3427 if (elm.text_type() == TextElement::CHAR_CLASS) {
3428 RegExpCharacterClass* cc = elm.char_class();
3431 if (cc->is_standard(zone()))
continue;
3433 int range_count = ranges->length();
3434 for (
int j = 0; j < range_count; j++) {
3435 ranges->
at(j).AddCaseEquivalents(ranges, is_ascii, zone());
3443 TextElement elm = elms_->at(elms_->length() - 1);
3444 return elm.cp_offset() + elm.length();
3450 if (elms_->length() != 1)
return NULL;
3451 TextElement elm = elms_->at(0);
3452 if (elm.text_type() != TextElement::CHAR_CLASS)
return NULL;
3453 RegExpCharacterClass* node = elm.char_class();
3458 if (node->is_negated()) {
3459 return ranges->length() == 0 ? on_success() :
NULL;
3461 if (ranges->length() != 1)
return NULL;
3463 if (compiler->
ascii()) {
3468 return ranges->
at(0).IsEverything(max_char) ? on_success() :
NULL;
3482 int recursion_depth = 0;
3483 while (node !=
this) {
3485 return kNodeIsTooComplexForGreedyLoops;
3488 if (node_length == kNodeIsTooComplexForGreedyLoops) {
3489 return kNodeIsTooComplexForGreedyLoops;
3491 length += node_length;
3501 AddAlternative(alt);
3502 loop_node_ = alt.
node();
3508 AddAlternative(alt);
3509 continue_node_ = alt.
node();
3517 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
3518 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
3528 trace->
Flush(compiler,
this);
3535 int ChoiceNode::CalculatePreloadCharacters(
RegExpCompiler* compiler,
3536 int eats_at_least) {
3537 int preload_characters =
Min(4, eats_at_least);
3539 bool ascii = compiler->
ascii();
3541 if (preload_characters > 4) preload_characters = 4;
3545 if (preload_characters == 3) preload_characters = 2;
3547 if (preload_characters > 2) preload_characters = 2;
3550 if (preload_characters > 1) preload_characters = 1;
3552 return preload_characters;
3561 : possible_success(),
3562 expects_preload(
false),
3564 quick_check_details() { }
3577 : alt_gens_(count, zone) {
3578 for (
int i = 0; i < count && i < kAFew; i++) {
3579 alt_gens_.Add(a_few_alt_gens_ + i, zone);
3581 for (
int i = kAFew; i < count; i++) {
3586 for (
int i = kAFew; i < alt_gens_.length(); i++) {
3587 delete alt_gens_[i];
3588 alt_gens_[i] =
NULL;
3593 return alt_gens_[i];
3597 static const int kAFew = 10;
3606 static const int kSpaceRanges[] = {
'\t',
'\r' + 1,
' ',
' ' + 1,
3607 0x00A0, 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B,
3608 0x2028, 0x202A, 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001,
3609 0xFEFF, 0xFF00, 0x10000 };
3610 static const int kSpaceRangeCount =
ARRAY_SIZE(kSpaceRanges);
3612 static const int kWordRanges[] = {
3613 '0',
'9' + 1,
'A',
'Z' + 1,
'_',
'_' + 1,
'a',
'z' + 1, 0x10000 };
3614 static const int kWordRangeCount =
ARRAY_SIZE(kWordRanges);
3615 static const int kDigitRanges[] = {
'0',
'9' + 1, 0x10000 };
3616 static const int kDigitRangeCount =
ARRAY_SIZE(kDigitRanges);
3617 static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 };
3618 static const int kSurrogateRangeCount =
ARRAY_SIZE(kSurrogateRanges);
3619 static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
3620 0x2028, 0x202A, 0x10000 };
3621 static const int kLineTerminatorRangeCount =
ARRAY_SIZE(kLineTerminatorRanges);
3625 SetInterval(
Interval(character, character));
3630 s_ =
AddRange(s_, kSpaceRanges, kSpaceRangeCount, interval);
3631 w_ =
AddRange(w_, kWordRanges, kWordRangeCount, interval);
3632 d_ =
AddRange(d_, kDigitRanges, kDigitRangeCount, interval);
3634 AddRange(surrogate_, kSurrogateRanges, kSurrogateRangeCount, interval);
3635 if (interval.
to() - interval.
from() >= kMapSize - 1) {
3636 if (map_count_ != kMapSize) {
3637 map_count_ = kMapSize;
3638 for (
int i = 0; i < kMapSize; i++) map_->at(i) =
true;
3642 for (
int i = interval.
from(); i <= interval.
to(); i++) {
3643 int mod_character = (i & kMask);
3644 if (!map_->at(mod_character)) {
3646 map_->at(mod_character) =
true;
3648 if (map_count_ == kMapSize)
return;
3655 if (map_count_ != kMapSize) {
3656 map_count_ = kMapSize;
3657 for (
int i = 0; i < kMapSize; i++) map_->at(i) =
true;
3665 compiler_(compiler) {
3666 if (compiler->
ascii()) {
3672 for (
int i = 0; i <
length; i++) {
3681 bool BoyerMooreLookahead::FindWorthwhileInterval(
int* from,
int* to) {
3682 int biggest_points = 0;
3685 const int kMaxMax = 32;
3686 for (
int max_number_of_chars = 4;
3687 max_number_of_chars < kMaxMax;
3688 max_number_of_chars *= 2) {
3690 FindBestInterval(max_number_of_chars, biggest_points, from, to);
3692 if (biggest_points == 0)
return false;
3703 int BoyerMooreLookahead::FindBestInterval(
3704 int max_number_of_chars,
int old_biggest_points,
int* from,
int* to) {
3705 int biggest_points = old_biggest_points;
3707 for (
int i = 0; i < length_; ) {
3708 while (i < length_ &&
Count(i) > max_number_of_chars) i++;
3709 if (i == length_)
break;
3710 int remembered_from = i;
3711 bool union_map[kSize];
3712 for (
int j = 0; j < kSize; j++) union_map[j] =
false;
3713 while (i < length_ &&
Count(i) <= max_number_of_chars) {
3714 BoyerMoorePositionInfo*
map = bitmaps_->at(i);
3715 for (
int j = 0; j < kSize; j++) union_map[j] |= map->at(j);
3719 for (
int j = 0; j < kSize; j++) {
3734 bool in_quickcheck_range = ((i - remembered_from < 4) ||
3735 (compiler_->
ascii() ? remembered_from <= 4 : remembered_from <= 2));
3738 int probability = (in_quickcheck_range ? kSize / 2 : kSize) - frequency;
3739 int points = (i - remembered_from) * probability;
3740 if (points > biggest_points) {
3741 *from = remembered_from;
3743 biggest_points = points;
3746 return biggest_points;
3755 int BoyerMooreLookahead::GetSkipTable(
int min_lookahead,
3757 Handle<ByteArray> boolean_skip_table) {
3760 const int kSkipArrayEntry = 0;
3761 const int kDontSkipArrayEntry = 1;
3763 for (
int i = 0; i < kSize; i++) {
3764 boolean_skip_table->set(i, kSkipArrayEntry);
3766 int skip = max_lookahead + 1 - min_lookahead;
3768 for (
int i = max_lookahead; i >= min_lookahead; i--) {
3769 BoyerMoorePositionInfo* map = bitmaps_->at(i);
3770 for (
int j = 0; j < kSize; j++) {
3772 boolean_skip_table->set(j, kDontSkipArrayEntry);
3785 int min_lookahead = 0;
3786 int max_lookahead = 0;
3788 if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead))
return false;
3790 bool found_single_character =
false;
3791 int single_character = 0;
3792 for (
int i = max_lookahead; i >= min_lookahead; i--) {
3795 (found_single_character && map->
map_count() != 0)) {
3796 found_single_character =
false;
3799 for (
int j = 0; j < kSize; j++) {
3801 found_single_character =
true;
3802 single_character = j;
3808 int lookahead_width = max_lookahead + 1 - min_lookahead;
3810 if (found_single_character && lookahead_width == 1 && max_lookahead < 3) {
3815 if (found_single_character) {
3819 if (max_char_ > kSize) {
3834 int skip_distance = GetSkipTable(
3835 min_lookahead, max_lookahead, boolean_skip_table);
3836 ASSERT(skip_distance != 0);
3932 for (
int i = 0; i < choice_count - 1; i++) {
3935 int guard_count = (guards ==
NULL) ? 0 : guards->length();
3936 for (
int j = 0; j < guard_count; j++) {
3943 if (limit_result ==
DONE)
return;
3946 int new_flush_budget = trace->
flush_budget() / choice_count;
3948 trace->
Flush(compiler,
this);
3954 Trace* current_trace = trace;
3957 bool greedy_loop =
false;
3958 Label greedy_loop_label;
3959 Trace counter_backtrack_trace;
3974 current_trace = &counter_backtrack_trace;
3975 Label greedy_match_failed;
3976 Trace greedy_match_trace;
3980 macro_assembler->
Bind(&loop_label);
3983 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
3984 macro_assembler->
Bind(&greedy_match_failed);
3987 Label second_choice;
3988 macro_assembler->
Bind(&second_choice);
3990 int first_normal_choice = greedy_loop ? 1 : 0;
3993 const int kEatsAtLeastNotYetInitialized = -1;
3994 int eats_at_least = kEatsAtLeastNotYetInitialized;
3996 bool skip_was_emitted =
false;
3998 if (!greedy_loop && choice_count == 2) {
4013 if (lookahead ==
NULL) {
4018 if (eats_at_least >= 1) {
4028 skip_was_emitted = lookahead->EmitSkipInstructions(macro_assembler);
4034 if (eats_at_least == kEatsAtLeastNotYetInitialized) {
4039 int preload_characters = CalculatePreloadCharacters(compiler, eats_at_least);
4041 bool preload_is_current = !skip_was_emitted &&
4043 bool preload_has_checked_bounds = preload_is_current;
4049 for (
int i = first_normal_choice; i < choice_count; i++) {
4054 int guard_count = (guards ==
NULL) ? 0 : guards->length();
4055 Trace new_trace(*current_trace);
4057 preload_characters :
4059 if (preload_has_checked_bounds) {
4065 bool generate_full_check_inline =
false;
4066 if (FLAG_regexp_optimization &&
4070 preload_has_checked_bounds,
4073 i < choice_count - 1)) {
4075 preload_is_current =
true;
4076 preload_has_checked_bounds =
true;
4080 if (i == choice_count - 1) {
4085 generate_full_check_inline =
true;
4088 if (i == choice_count - 1 && !greedy_loop) {
4098 if (i != first_normal_choice) {
4102 if (i < choice_count - 1) {
4105 generate_full_check_inline =
true;
4107 if (generate_full_check_inline) {
4111 for (
int j = 0; j < guard_count; j++) {
4112 GenerateGuard(macro_assembler, guards->
at(j), &new_trace);
4114 alternative.
node()->
Emit(compiler, &new_trace);
4115 preload_is_current =
false;
4120 macro_assembler->
Bind(&greedy_loop_label);
4125 macro_assembler->
GoTo(&second_choice);
4131 for (
int i = first_normal_choice; i < choice_count - 1; i++) {
4133 Trace new_trace(*current_trace);
4140 EmitOutOfLineContinuation(compiler,
4150 void ChoiceNode::EmitOutOfLineContinuation(
RegExpCompiler* compiler,
4154 int preload_characters,
4155 bool next_expects_preload) {
4160 Trace out_of_line_trace(*trace);
4161 out_of_line_trace.set_characters_preloaded(preload_characters);
4165 int guard_count = (guards ==
NULL) ? 0 : guards->length();
4166 if (next_expects_preload) {
4167 Label reload_current_char;
4168 out_of_line_trace.set_backtrack(&reload_current_char);
4169 for (
int j = 0; j < guard_count; j++) {
4170 GenerateGuard(macro_assembler, guards->
at(j), &out_of_line_trace);
4172 alternative.
node()->
Emit(compiler, &out_of_line_trace);
4173 macro_assembler->
Bind(&reload_current_char);
4180 preload_characters);
4181 macro_assembler->
GoTo(&(alt_gen->
after));
4183 out_of_line_trace.set_backtrack(&(alt_gen->
after));
4184 for (
int j = 0; j < guard_count; j++) {
4185 GenerateGuard(macro_assembler, guards->
at(j), &out_of_line_trace);
4187 alternative.
node()->
Emit(compiler, &out_of_line_trace);
4195 if (limit_result ==
DONE)
return;
4200 switch (action_type_) {
4203 new_capture(data_.u_position_register.reg,
4204 data_.u_position_register.is_capture,
4206 Trace new_trace = *trace;
4213 new_increment(data_.u_increment_register.reg);
4214 Trace new_trace = *trace;
4221 new_set(data_.u_store_register.reg, data_.u_store_register.value);
4222 Trace new_trace = *trace;
4229 new_capture(
Interval(data_.u_clear_captures.range_from,
4230 data_.u_clear_captures.range_to));
4231 Trace new_trace = *trace;
4238 trace->
Flush(compiler,
this);
4241 data_.u_submatch.current_position_register, 0);
4243 data_.u_submatch.stack_pointer_register);
4248 int start_pos_reg = data_.u_empty_match_check.start_register;
4250 int rep_reg = data_.u_empty_match_check.repetition_register;
4253 if (know_dist && !has_minimum && stored_pos == trace->
cp_offset()) {
4257 }
else if (know_dist && stored_pos < trace->cp_offset()) {
4262 trace->
Flush(compiler,
this);
4264 Label skip_empty_check;
4268 int limit = data_.u_empty_match_check.repetition_limit;
4269 assembler->
IfRegisterLT(rep_reg, limit, &skip_empty_check);
4275 assembler->
Bind(&skip_empty_check);
4282 trace->
Flush(compiler,
this);
4286 data_.u_submatch.current_position_register);
4288 data_.u_submatch.stack_pointer_register);
4290 if (clear_register_count == 0) {
4294 int clear_registers_from = data_.u_submatch.clear_register_from;
4295 Label clear_registers_backtrack;
4296 Trace new_trace = *trace;
4300 assembler->
Bind(&clear_registers_backtrack);
4301 int clear_registers_to = clear_registers_from + clear_register_count - 1;
4302 assembler->
ClearRegisters(clear_registers_from, clear_registers_to);
4317 trace->
Flush(compiler,
this);
4322 if (limit_result ==
DONE)
return;
4347 explicit DotPrinter(
bool ignore_case)
4348 : ignore_case_(ignore_case),
4350 void PrintNode(
const char* label, RegExpNode* node);
4351 void Visit(RegExpNode* node);
4352 void PrintAttributes(RegExpNode* from);
4353 StringStream* stream() {
return &
stream_; }
4354 void PrintOnFailure(RegExpNode* from, RegExpNode* to);
4355 #define DECLARE_VISIT(Type) \
4356 virtual void Visit##Type(Type##Node* that);
4358 #undef DECLARE_VISIT
4361 HeapStringAllocator alloc_;
4366 void DotPrinter::PrintNode(
const char* label, RegExpNode* node) {
4367 stream()->Add(
"digraph G {\n graph [label=\"");
4368 for (
int i = 0; label[i]; i++) {
4371 stream()->Add(
"\\\\");
4374 stream()->Add(
"\"");
4377 stream()->Put(label[i]);
4381 stream()->Add(
"\"];\n");
4383 stream()->Add(
"}\n");
4384 printf(
"%s", stream()->
ToCString().
get());
4388 void DotPrinter::Visit(RegExpNode* node) {
4389 if (node->info()->visited)
return;
4390 node->info()->visited =
true;
4395 void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
4396 stream()->Add(
" n%p -> n%p [style=dotted];\n", from, on_failure);
4401 class TableEntryBodyPrinter {
4403 TableEntryBodyPrinter(StringStream* stream, ChoiceNode* choice)
4404 :
stream_(stream), choice_(choice) { }
4405 void Call(
uc16 from, DispatchTable::Entry entry) {
4406 OutSet* out_set = entry.out_set();
4408 if (out_set->Get(i)) {
4409 stream()->Add(
" n%p:s%io%i -> n%p;\n",
4413 choice()->alternatives()->at(i).node());
4418 StringStream* stream() {
return stream_; }
4419 ChoiceNode* choice() {
return choice_; }
4421 ChoiceNode* choice_;
4425 class TableEntryHeaderPrinter {
4427 explicit TableEntryHeaderPrinter(StringStream* stream)
4429 void Call(
uc16 from, DispatchTable::Entry entry) {
4435 stream()->Add(
"{\\%k-\\%k|{", from, entry.to());
4436 OutSet* out_set = entry.out_set();
4439 if (out_set->Get(i)) {
4440 if (priority > 0) stream()->Add(
"|");
4441 stream()->Add(
"<s%io%i> %i", from, i, priority);
4445 stream()->Add(
"}}");
4450 StringStream* stream() {
return stream_; }
4455 class AttributePrinter {
4457 explicit AttributePrinter(DotPrinter* out)
4458 : out_(out), first_(
true) { }
4459 void PrintSeparator() {
4463 out_->stream()->Add(
"|");
4466 void PrintBit(
const char*
name,
bool value) {
4469 out_->stream()->Add(
"{%s}", name);
4471 void PrintPositive(
const char* name,
int value) {
4472 if (value < 0)
return;
4474 out_->stream()->Add(
"{%s|%x}", name, value);
4482 void DotPrinter::PrintAttributes(RegExpNode* that) {
4483 stream()->Add(
" a%p [shape=Mrecord, color=grey, fontcolor=grey, "
4484 "margin=0.1, fontsize=10, label=\"{",
4486 AttributePrinter printer(
this);
4487 NodeInfo*
info = that->info();
4488 printer.PrintBit(
"NI", info->follows_newline_interest);
4489 printer.PrintBit(
"WI", info->follows_word_interest);
4490 printer.PrintBit(
"SI", info->follows_start_interest);
4491 Label* label = that->label();
4492 if (label->is_bound())
4493 printer.PrintPositive(
"@", label->pos());
4494 stream()->Add(
"}\"];\n");
4495 stream()->Add(
" a%p -> n%p [style=dashed, color=grey, "
4496 "arrowhead=none];\n", that, that);
4500 static const bool kPrintDispatchTable =
false;
4501 void DotPrinter::VisitChoice(ChoiceNode* that) {
4502 if (kPrintDispatchTable) {
4503 stream()->Add(
" n%p [shape=Mrecord, label=\"", that);
4504 TableEntryHeaderPrinter header_printer(stream());
4505 that->GetTable(ignore_case_)->ForEach(&header_printer);
4506 stream()->Add(
"\"]\n", that);
4507 PrintAttributes(that);
4508 TableEntryBodyPrinter body_printer(stream(), that);
4509 that->GetTable(ignore_case_)->ForEach(&body_printer);
4511 stream()->Add(
" n%p [shape=Mrecord, label=\"?\"];\n", that);
4512 for (
int i = 0; i < that->alternatives()->length(); i++) {
4513 GuardedAlternative alt = that->alternatives()->at(i);
4514 stream()->Add(
" n%p -> n%p;\n", that, alt.node());
4517 for (
int i = 0; i < that->alternatives()->length(); i++) {
4518 GuardedAlternative alt = that->alternatives()->at(i);
4519 alt.node()->Accept(
this);
4524 void DotPrinter::VisitText(TextNode* that) {
4525 Zone* zone = that->zone();
4526 stream()->Add(
" n%p [label=\"", that);
4527 for (
int i = 0; i < that->elements()->length(); i++) {
4528 if (i > 0) stream()->Add(
" ");
4529 TextElement elm = that->elements()->at(i);
4530 switch (elm.text_type()) {
4531 case TextElement::ATOM: {
4532 stream()->Add(
"'%w'", elm.atom()->data());
4535 case TextElement::CHAR_CLASS: {
4536 RegExpCharacterClass* node = elm.char_class();
4538 if (node->is_negated())
4540 for (
int j = 0; j < node->ranges(zone)->length(); j++) {
4541 CharacterRange range = node->ranges(zone)->at(j);
4542 stream()->Add(
"%k-%k", range.from(), range.to());
4551 stream()->Add(
"\", shape=box, peripheries=2];\n");
4552 PrintAttributes(that);
4553 stream()->Add(
" n%p -> n%p;\n", that, that->on_success());
4554 Visit(that->on_success());
4558 void DotPrinter::VisitBackReference(BackReferenceNode* that) {
4559 stream()->Add(
" n%p [label=\"$%i..$%i\", shape=doubleoctagon];\n",
4561 that->start_register(),
4562 that->end_register());
4563 PrintAttributes(that);
4564 stream()->Add(
" n%p -> n%p;\n", that, that->on_success());
4565 Visit(that->on_success());
4569 void DotPrinter::VisitEnd(EndNode* that) {
4570 stream()->Add(
" n%p [style=bold, shape=point];\n", that);
4571 PrintAttributes(that);
4575 void DotPrinter::VisitAssertion(AssertionNode* that) {
4576 stream()->Add(
" n%p [", that);
4577 switch (that->assertion_type()) {
4579 stream()->Add(
"label=\"$\", shape=septagon");
4582 stream()->Add(
"label=\"^\", shape=septagon");
4585 stream()->Add(
"label=\"\\b\", shape=septagon");
4588 stream()->Add(
"label=\"\\B\", shape=septagon");
4591 stream()->Add(
"label=\"(?<=\\n)\", shape=septagon");
4594 stream()->Add(
"];\n");
4595 PrintAttributes(that);
4596 RegExpNode* successor = that->on_success();
4597 stream()->Add(
" n%p -> n%p;\n", that, successor);
4602 void DotPrinter::VisitAction(ActionNode* that) {
4603 stream()->Add(
" n%p [", that);
4604 switch (that->action_type_) {
4606 stream()->Add(
"label=\"$%i:=%i\", shape=octagon",
4607 that->data_.u_store_register.reg,
4608 that->data_.u_store_register.value);
4611 stream()->Add(
"label=\"$%i++\", shape=octagon",
4612 that->data_.u_increment_register.reg);
4615 stream()->Add(
"label=\"$%i:=$pos\", shape=octagon",
4616 that->data_.u_position_register.reg);
4619 stream()->Add(
"label=\"$%i:=$pos,begin\", shape=septagon",
4620 that->data_.u_submatch.current_position_register);
4623 stream()->Add(
"label=\"escape\", shape=septagon");
4626 stream()->Add(
"label=\"$%i=$pos?,$%i<%i?\", shape=septagon",
4627 that->data_.u_empty_match_check.start_register,
4628 that->data_.u_empty_match_check.repetition_register,
4629 that->data_.u_empty_match_check.repetition_limit);
4632 stream()->Add(
"label=\"clear $%i to $%i\", shape=septagon",
4633 that->data_.u_clear_captures.range_from,
4634 that->data_.u_clear_captures.range_to);
4638 stream()->Add(
"];\n");
4639 PrintAttributes(that);
4640 RegExpNode* successor = that->on_success();
4641 stream()->Add(
" n%p -> n%p;\n", that, successor);
4646 class DispatchTableDumper {
4648 explicit DispatchTableDumper(StringStream* stream) :
stream_(stream) { }
4649 void Call(
uc16 key, DispatchTable::Entry entry);
4650 StringStream* stream() {
return stream_; }
4656 void DispatchTableDumper::Call(
uc16 key, DispatchTable::Entry entry) {
4657 stream()->Add(
"[%k-%k]: {", key, entry.to());
4658 OutSet* set = entry.out_set();
4665 stream()->Add(
", ");
4667 stream()->Add(
"%i", i);
4670 stream()->Add(
"}\n");
4675 HeapStringAllocator alloc;
4676 StringStream stream(&alloc);
4677 DispatchTableDumper dumper(&stream);
4678 tree()->ForEach(&dumper);
4686 DotPrinter printer(ignore_case);
4687 printer.PrintNode(label, node);
4697 RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
4698 RegExpNode* on_success) {
4699 ZoneList<TextElement>* elms =
4700 new(compiler->zone()) ZoneList<TextElement>(1, compiler->zone());
4701 elms->Add(TextElement::Atom(
this), compiler->zone());
4702 return new(compiler->zone()) TextNode(elms, on_success);
4706 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
4707 RegExpNode* on_success) {
4708 return new(compiler->zone()) TextNode(elements(), on_success);
4712 static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges,
4713 const int* special_class,
4716 ASSERT(special_class[length] == 0x10000);
4717 ASSERT(ranges->length() != 0);
4719 ASSERT(special_class[0] != 0);
4720 if (ranges->length() != (length >> 1) + 1) {
4723 CharacterRange range = ranges->at(0);
4724 if (range.from() != 0) {
4727 for (
int i = 0; i < length; i += 2) {
4728 if (special_class[i] != (range.to() + 1)) {
4731 range = ranges->at((i >> 1) + 1);
4732 if (special_class[i+1] != range.from()) {
4736 if (range.to() != 0xffff) {
4743 static bool CompareRanges(ZoneList<CharacterRange>* ranges,
4744 const int* special_class,
4747 ASSERT(special_class[length] == 0x10000);
4748 if (ranges->length() * 2 != length) {
4751 for (
int i = 0; i < length; i += 2) {
4752 CharacterRange range = ranges->at(i >> 1);
4753 if (range.from() != special_class[i] ||
4754 range.to() != special_class[i + 1] - 1) {
4762 bool RegExpCharacterClass::is_standard(Zone* zone) {
4768 if (set_.is_standard()) {
4771 if (CompareRanges(set_.ranges(zone), kSpaceRanges, kSpaceRangeCount)) {
4772 set_.set_standard_set_type(
's');
4775 if (CompareInverseRanges(set_.ranges(zone), kSpaceRanges, kSpaceRangeCount)) {
4776 set_.set_standard_set_type(
'S');
4779 if (CompareInverseRanges(set_.ranges(zone),
4780 kLineTerminatorRanges,
4781 kLineTerminatorRangeCount)) {
4782 set_.set_standard_set_type(
'.');
4785 if (CompareRanges(set_.ranges(zone),
4786 kLineTerminatorRanges,
4787 kLineTerminatorRangeCount)) {
4788 set_.set_standard_set_type(
'n');
4791 if (CompareRanges(set_.ranges(zone), kWordRanges, kWordRangeCount)) {
4792 set_.set_standard_set_type(
'w');
4795 if (CompareInverseRanges(set_.ranges(zone), kWordRanges, kWordRangeCount)) {
4796 set_.set_standard_set_type(
'W');
4803 RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
4804 RegExpNode* on_success) {
4805 return new(compiler->zone()) TextNode(
this, on_success);
4809 RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
4810 RegExpNode* on_success) {
4811 ZoneList<RegExpTree*>* alternatives = this->alternatives();
4812 int length = alternatives->length();
4813 ChoiceNode* result =
4814 new(compiler->zone()) ChoiceNode(length, compiler->zone());
4815 for (
int i = 0; i < length; i++) {
4816 GuardedAlternative alternative(alternatives->at(i)->ToNode(compiler,
4818 result->AddAlternative(alternative);
4824 RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler,
4825 RegExpNode* on_success) {
4826 return ToNode(min(),
4841 : compiler_(compiler),
4842 saved_expansion_factor_(compiler->current_expansion_factor()),
4845 if (ok_to_expand_) {
4848 ok_to_expand_ =
false;
4851 int new_factor = saved_expansion_factor_ * factor;
4866 int saved_expansion_factor_;
4873 RegExpNode* RegExpQuantifier::ToNode(
int min,
4877 RegExpCompiler* compiler,
4878 RegExpNode* on_success,
4879 bool not_at_start) {
4900 static const int kMaxUnrolledMinMatches = 3;
4901 static const int kMaxUnrolledMaxMatches = 3;
4902 if (max == 0)
return on_success;
4903 bool body_can_be_empty = (body->min_match() == 0);
4905 Interval capture_registers = body->CaptureRegisters();
4906 bool needs_capture_clearing = !capture_registers.is_empty();
4907 Zone* zone = compiler->zone();
4909 if (body_can_be_empty) {
4910 body_start_reg = compiler->AllocateRegister();
4911 }
else if (FLAG_regexp_optimization && !needs_capture_clearing) {
4915 RegExpExpansionLimiter limiter(
4916 compiler, min + ((max != min) ? 1 : 0));
4917 if (min > 0 && min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) {
4918 int new_max = (max == kInfinity) ? max : max - min;
4921 RegExpNode* answer = ToNode(
4922 0, new_max, is_greedy, body, compiler, on_success,
true);
4926 for (
int i = 0; i < min; i++) {
4927 answer = body->ToNode(compiler, answer);
4932 if (max <= kMaxUnrolledMaxMatches && min == 0) {
4934 RegExpExpansionLimiter limiter(compiler, max);
4935 if (limiter.ok_to_expand()) {
4937 RegExpNode* answer = on_success;
4938 for (
int i = 0; i < max; i++) {
4939 ChoiceNode* alternation =
new(zone) ChoiceNode(2, zone);
4941 alternation->AddAlternative(
4942 GuardedAlternative(body->ToNode(compiler, answer)));
4943 alternation->AddAlternative(GuardedAlternative(on_success));
4945 alternation->AddAlternative(GuardedAlternative(on_success));
4946 alternation->AddAlternative(
4947 GuardedAlternative(body->ToNode(compiler, answer)));
4949 answer = alternation;
4950 if (not_at_start) alternation->set_not_at_start();
4956 bool has_min = min > 0;
4958 bool needs_counter = has_min || has_max;
4959 int reg_ctr = needs_counter
4960 ? compiler->AllocateRegister()
4962 LoopChoiceNode* center =
new(zone) LoopChoiceNode(body->min_match() == 0,
4964 if (not_at_start) center->set_not_at_start();
4965 RegExpNode* loop_return = needs_counter
4967 : static_cast<RegExpNode*>(center);
4968 if (body_can_be_empty) {
4976 RegExpNode* body_node = body->ToNode(compiler, loop_return);
4977 if (body_can_be_empty) {
4982 if (needs_capture_clearing) {
4986 GuardedAlternative body_alt(body_node);
4989 new(zone) Guard(reg_ctr,
Guard::LT, max);
4990 body_alt.AddGuard(body_guard, zone);
4992 GuardedAlternative rest_alt(on_success);
4994 Guard* rest_guard =
new(compiler->zone()) Guard(reg_ctr,
Guard::GEQ, min);
4995 rest_alt.AddGuard(rest_guard, zone);
4998 center->AddLoopAlternative(body_alt);
4999 center->AddContinueAlternative(rest_alt);
5001 center->AddContinueAlternative(rest_alt);
5002 center->AddLoopAlternative(body_alt);
5004 if (needs_counter) {
5012 RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
5013 RegExpNode* on_success) {
5015 Zone* zone = compiler->zone();
5017 switch (assertion_type()) {
5020 case START_OF_INPUT:
5032 int stack_pointer_register = compiler->AllocateRegister();
5033 int position_register = compiler->AllocateRegister();
5035 ChoiceNode* result =
new(zone) ChoiceNode(2, zone);
5037 ZoneList<CharacterRange>* newline_ranges =
5038 new(zone) ZoneList<CharacterRange>(3, zone);
5040 RegExpCharacterClass* newline_atom =
new(zone) RegExpCharacterClass(
'n');
5041 TextNode* newline_matcher =
new(zone) TextNode(
5050 stack_pointer_register,
5054 GuardedAlternative eol_alternative(end_of_line);
5055 result->AddAlternative(eol_alternative);
5057 result->AddAlternative(end_alternative);
5067 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
5068 RegExpNode* on_success) {
5069 return new(compiler->zone())
5070 BackReferenceNode(RegExpCapture::StartRegister(index()),
5071 RegExpCapture::EndRegister(index()),
5076 RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
5077 RegExpNode* on_success) {
5082 RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
5083 RegExpNode* on_success) {
5084 int stack_pointer_register = compiler->AllocateRegister();
5085 int position_register = compiler->AllocateRegister();
5087 const int registers_per_capture = 2;
5088 const int register_of_first_capture = 2;
5089 int register_count = capture_count_ * registers_per_capture;
5090 int register_start =
5091 register_of_first_capture + capture_from_ * registers_per_capture;
5093 RegExpNode* success;
5094 if (is_positive()) {
5096 stack_pointer_register,
5117 Zone* zone = compiler->zone();
5119 GuardedAlternative body_alt(
5122 success =
new(zone) NegativeSubmatchSuccess(stack_pointer_register,
5127 ChoiceNode* choice_node =
5128 new(zone) NegativeLookaheadChoiceNode(body_alt,
5129 GuardedAlternative(on_success),
5138 RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler,
5139 RegExpNode* on_success) {
5140 return ToNode(body(), index(), compiler, on_success);
5144 RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
5146 RegExpCompiler* compiler,
5147 RegExpNode* on_success) {
5148 int start_reg = RegExpCapture::StartRegister(index);
5149 int end_reg = RegExpCapture::EndRegister(index);
5151 RegExpNode* body_node = body->ToNode(compiler, store_end);
5156 RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
5157 RegExpNode* on_success) {
5158 ZoneList<RegExpTree*>* children = nodes();
5159 RegExpNode* current = on_success;
5160 for (
int i = children->length() - 1; i >= 0; i--) {
5161 current = children->at(i)->ToNode(compiler, current);
5167 static void AddClass(
const int* elmv,
5169 ZoneList<CharacterRange>* ranges,
5172 ASSERT(elmv[elmc] == 0x10000);
5173 for (
int i = 0; i < elmc; i += 2) {
5174 ASSERT(elmv[i] < elmv[i + 1]);
5175 ranges->Add(CharacterRange(elmv[i], elmv[i + 1] - 1), zone);
5180 static void AddClassNegated(
const int *elmv,
5182 ZoneList<CharacterRange>* ranges,
5185 ASSERT(elmv[elmc] == 0x10000);
5186 ASSERT(elmv[0] != 0x0000);
5189 for (
int i = 0; i < elmc; i += 2) {
5190 ASSERT(last <= elmv[i] - 1);
5191 ASSERT(elmv[i] < elmv[i + 1]);
5192 ranges->Add(CharacterRange(last, elmv[i] - 1), zone);
5204 AddClass(kSpaceRanges, kSpaceRangeCount, ranges, zone);
5207 AddClassNegated(kSpaceRanges, kSpaceRangeCount, ranges, zone);
5210 AddClass(kWordRanges, kWordRangeCount, ranges, zone);
5213 AddClassNegated(kWordRanges, kWordRangeCount, ranges, zone);
5216 AddClass(kDigitRanges, kDigitRangeCount, ranges, zone);
5219 AddClassNegated(kDigitRanges, kDigitRangeCount, ranges, zone);
5222 AddClassNegated(kLineTerminatorRanges,
5223 kLineTerminatorRangeCount,
5236 AddClass(kLineTerminatorRanges,
5237 kLineTerminatorRangeCount,
5257 : included_(included),
5258 excluded_(excluded),
5290 for (
int i = 0; i < base->length(); i++)
5292 for (
int i = 0; i < overlay.
length(); i += 2) {
5307 if (is_ascii && !RangeContainsLatin1Equivalents(*
this)) {
5312 if (top == bottom) {
5315 for (
int i = 0; i < length; i++) {
5316 uc32 chr = chars[i];
5317 if (chr != bottom) {
5342 while (pos <= top) {
5349 block_end = range[0];
5351 int end = (block_end > top) ? top : block_end;
5353 for (
int i = 0; i < length; i++) {
5355 uc16 range_from = c - (block_end - pos);
5356 uc16 range_to = c - (block_end - end);
5357 if (!(bottom <= range_from && range_to <= top)) {
5369 int n = ranges->length();
5370 if (n <= 1)
return true;
5371 int max = ranges->
at(0).to();
5372 for (
int i = 1; i < n; i++) {
5374 if (next_range.
from() <= max + 1)
return false;
5375 max = next_range.
to();
5382 if (ranges_ ==
NULL) {
5392 static void MoveRanges(ZoneList<CharacterRange>* list,
5398 for (
int i = count - 1; i >= 0; i--) {
5399 list->at(to + i) = list->at(from + i);
5402 for (
int i = 0; i < count; i++) {
5403 list->at(to + i) = list->at(from + i);
5409 static int InsertRangeInCanonicalList(ZoneList<CharacterRange>* list,
5411 CharacterRange insert) {
5417 uc16 from = insert.from();
5418 uc16 to = insert.to();
5420 int end_pos = count;
5421 for (
int i = count - 1; i >= 0; i--) {
5422 CharacterRange current = list->at(i);
5423 if (current.from() > to + 1) {
5425 }
else if (current.to() + 1 < from) {
5438 if (start_pos == end_pos) {
5440 if (start_pos < count) {
5441 MoveRanges(list, start_pos, start_pos + 1, count - start_pos);
5443 list->at(start_pos) = insert;
5446 if (start_pos + 1 == end_pos) {
5448 CharacterRange to_replace = list->at(start_pos);
5449 int new_from =
Min(to_replace.from(), from);
5450 int new_to =
Max(to_replace.to(), to);
5451 list->at(start_pos) = CharacterRange(new_from, new_to);
5457 int new_from =
Min(list->at(start_pos).from(), from);
5458 int new_to =
Max(list->at(end_pos - 1).to(), to);
5459 if (end_pos < count) {
5460 MoveRanges(list, end_pos, start_pos + 1, count - end_pos);
5462 list->at(start_pos) = CharacterRange(new_from, new_to);
5463 return count - (end_pos - start_pos) + 1;
5470 if (ranges_ ==
NULL)
return;
5476 if (character_ranges->length() <= 1)
return;
5479 int n = character_ranges->length();
5480 int max = character_ranges->
at(0).to();
5484 if (current.
from() <= max + 1) {
5499 int num_canonical = i;
5501 num_canonical = InsertRangeInCanonicalList(character_ranges,
5503 character_ranges->
at(read));
5506 character_ranges->Rewind(num_canonical);
5517 int range_count = ranges->length();
5520 if (range_count > 0 && ranges->
at(0).from() == 0) {
5521 from = ranges->
at(0).to();
5524 while (i < range_count) {
5544 if (successors(zone) !=
NULL) {
5545 for (
int i = 0; i < successors(zone)->length(); i++) {
5546 OutSet* successor = successors(zone)->at(i);
5547 if (successor->
Get(value))
5554 result->Set(value, zone);
5555 successors(zone)->Add(result, zone);
5560 void OutSet::Set(
unsigned value,
Zone *zone) {
5562 first_ |= (1 << value);
5564 if (remaining_ ==
NULL)
5565 remaining_ =
new(zone) ZoneList<unsigned>(1, zone);
5566 if (remaining_->is_empty() || !remaining_->
Contains(value))
5567 remaining_->
Add(value, zone);
5574 return (first_ & (1 << value)) != 0;
5575 }
else if (remaining_ ==
NULL) {
5578 return remaining_->
Contains(value);
5589 if (tree()->is_empty()) {
5594 empty()->
Extend(value, zone)));
5600 if (tree()->FindGreatestLessThan(current.
from(), &loc)) {
5601 Entry* entry = &loc.value();
5606 if (entry->
from() < current.
from() && entry->
to() >= current.
from()) {
5613 entry->
set_to(left.to());
5619 loc.set_value(
Entry(right.from(),
5625 if (tree()->FindLeastGreaterThan(current.
from(), &loc) &&
5626 (loc.value().from() <= current.
to()) &&
5627 (loc.value().to() >= current.
from())) {
5628 Entry* entry = &loc.value();
5632 if (current.
from() < entry->
from()) {
5637 empty()->
Extend(value, zone)));
5643 if (entry->
to() > current.
to()) {
5646 ins.set_value(
Entry(current.
to() + 1,
5668 empty()->
Extend(value, zone)));
5677 if (!tree()->FindGreatestLessThan(value, &loc))
5679 Entry* entry = &loc.value();
5680 if (value <= entry->to())
5693 if (check.HasOverflowed()) {
5694 fail(
"Stack overflow");
5706 void Analysis::VisitEnd(
EndNode* that) {
5712 int element_count =
elements()->length();
5716 for (
int i = 0; i < element_count; i++) {
5718 elm.set_cp_offset(cp_offset);
5719 cp_offset += elm.length();
5724 void Analysis::VisitText(
TextNode* that) {
5735 void Analysis::VisitAction(ActionNode* that) {
5736 RegExpNode* target = that->on_success();
5741 that->info()->AddFromFollowing(target->info());
5746 void Analysis::VisitChoice(ChoiceNode* that) {
5747 NodeInfo* info = that->info();
5748 for (
int i = 0; i < that->alternatives()->length(); i++) {
5749 RegExpNode* node = that->alternatives()->at(i).node();
5754 info->AddFromFollowing(node->info());
5761 for (
int i = 0; i < that->
alternatives()->length(); i++) {
5783 void Analysis::VisitAssertion(AssertionNode* that) {
5791 bool not_at_start) {
5806 bool not_at_start) {
5808 budget = (budget - 1) / alts->length();
5809 for (
int i = 0; i < alts->length(); i++) {
5825 bool not_at_start) {
5826 if (initial_offset >= bm->
length())
return;
5827 int offset = initial_offset;
5829 for (
int i = 0; i <
elements()->length(); i++) {
5830 if (offset >= bm->
length()) {
5831 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5835 if (text.text_type() == TextElement::ATOM) {
5836 RegExpAtom* atom = text.atom();
5837 for (
int j = 0; j < atom->length(); j++, offset++) {
5838 if (offset >= bm->
length()) {
5839 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5842 uc16 character = atom->data()[j];
5845 int length = GetCaseIndependentLetters(
5850 for (
int j = 0; j < length; j++) {
5851 bm->
Set(offset, chars[j]);
5854 if (character <= max_char) bm->
Set(offset, character);
5858 ASSERT_EQ(TextElement::CHAR_CLASS, text.text_type());
5859 RegExpCharacterClass* char_class = text.char_class();
5861 if (char_class->is_negated()) {
5864 for (
int k = 0; k < ranges->length(); k++) {
5866 if (range.
from() > max_char)
continue;
5867 int to =
Min(max_char, static_cast<int>(range.
to()));
5874 if (offset >= bm->
length()) {
5875 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5882 if (initial_offset == 0)
set_bm_info(not_at_start, bm);
5890 void DispatchTableConstructor::VisitEnd(
EndNode* that) {
5898 for (
int i = 0; i < alternatives->length(); i++) {
5900 alternatives->
at(i).node()->Accept(
this);
5909 : constructor_(constructor) { }
5922 void DispatchTableConstructor::VisitChoice(
ChoiceNode* node) {
5931 void DispatchTableConstructor::VisitBackReference(BackReferenceNode* that) {
5938 void DispatchTableConstructor::VisitAssertion(AssertionNode* that) {
5939 RegExpNode* target = that->on_success();
5940 target->Accept(
this);
5944 static int CompareRangeByFrom(
const CharacterRange* a,
5945 const CharacterRange* b) {
5946 return Compare<uc16>(a->from(), b->from());
5951 ranges->
Sort(CompareRangeByFrom);
5953 for (
int i = 0; i < ranges->length(); i++) {
5955 if (last < range.
from())
5957 if (range.
to() >= last) {
5961 last = range.
to() + 1;
5969 void DispatchTableConstructor::VisitText(
TextNode* that) {
5971 switch (elm.text_type()) {
5972 case TextElement::ATOM: {
5973 uc16 c = elm.atom()->data()[0];
5977 case TextElement::CHAR_CLASS: {
5978 RegExpCharacterClass* tree = elm.char_class();
5979 ZoneList<CharacterRange>* ranges = tree->ranges(that->
zone());
5980 if (tree->is_negated()) {
5983 for (
int i = 0; i < ranges->length(); i++)
5995 void DispatchTableConstructor::VisitAction(ActionNode* that) {
5996 RegExpNode* target = that->on_success();
5997 target->Accept(
this);
6011 return IrregexpRegExpTooBig(zone->
isolate());
6019 int chars_sampled = 0;
6020 int half_way = (sample_subject->length() -
kSampleSize) / 2;
6021 for (
int i =
Max(0, half_way);
6022 i < sample_subject->length() && chars_sampled <
kSampleSize;
6023 i++, chars_sampled++) {
6036 if (!is_start_anchored) {
6040 RegExpQuantifier::ToNode(0,
6041 RegExpTree::kInfinity,
6043 new(zone) RegExpCharacterClass(
'*'),
6054 new(zone)
TextNode(
new(zone) RegExpCharacterClass(
'*'), loop_node)));
6055 node = first_step_node;
6071 Analysis analysis(ignore_case, is_ascii);
6079 #ifndef V8_INTERPRETED_REGEXP
6086 #if V8_TARGET_ARCH_IA32
6089 #elif V8_TARGET_ARCH_X64
6092 #elif V8_TARGET_ARCH_ARM
6095 #elif V8_TARGET_ARCH_ARM64
6098 #elif V8_TARGET_ARCH_MIPS
6102 #error "Unsupported architecture"
6105 #else // V8_INTERPRETED_REGEXP
6108 RegExpMacroAssemblerIrregexp macro_assembler(codes, zone);
6109 #endif // V8_INTERPRETED_REGEXP
6113 static const int kMaxBacksearchLimit = 1024;
6114 if (is_end_anchored &&
6115 !is_start_anchored &&
6116 max_length < kMaxBacksearchLimit) {
6117 macro_assembler.SetCurrentPositionFromEnd(max_length);
6121 macro_assembler.set_global_mode(
6127 return compiler.
Assemble(¯o_assembler,
void SetInterval(const Interval &interval)
AlternativeGenerationList(int count, Zone *zone)
virtual void WriteStackPointerToRegister(int reg)=0
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
static Handle< Object > New(Handle< JSFunction > func, int argc, Handle< Object > argv[], bool *pending_exception)
bool EmitCharacterFunction(Isolate *isolate, RegExpCompiler *compiler, uc16 c, Label *on_failure, int cp_offset, bool check, bool preloaded)
Failure * StackOverflow()
struct v8::internal::ActionNode::@17::@22 u_empty_match_check
void FlattenString(Handle< String > string)
int GreedyLoopTextLengthForAlternative(GuardedAlternative *alternative)
static const int kIrregexpMaxRegisterCountIndex
double total_regexp_code_generated()
bool Contains(const T &elm) const
#define DECLARE_VISIT(type)
static Vector< const int > GetWordBounds()
#define ASSERT_RESULT(expr)
virtual void GoTo(Label *label)=0
static AssertionNode * AtStart(RegExpNode *on_success)
const char * ToCString(const v8::String::Utf8Value &value)
void SetInterval(int map_number, const Interval &interval)
static ActionNode * SetRegister(int reg, int val, RegExpNode *on_success)
RegExpEngine::CompilationResult Assemble(RegExpMacroAssembler *assembler, RegExpNode *start, int capture_count, Handle< String > pattern)
static Code * IrregexpNativeCode(FixedArray *re, bool is_ascii)
void set(int index, Object *value)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths true
CompilationCache * compilation_cache()
CharacterRangeSplitter(ZoneList< CharacterRange > **included, ZoneList< CharacterRange > **excluded, Zone *zone)
void PrintF(const char *format,...)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf map
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static String * cast(Object *obj)
static ActionNode * BeginSubmatch(int stack_pointer_reg, int position_reg, RegExpNode *on_success)
virtual int EatsAtLeast(int still_to_find, int recursion_depth, bool not_at_start)
CodeTracer * GetCodeTracer()
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static const int kMaxUtf16CodeUnit
void set_characters(int characters)
unibrow::Mapping< unibrow::Ecma262UnCanonicalize > * jsregexp_uncanonicalize()
VisitMarker(NodeInfo *info)
virtual RegExpNode * GetSuccessorOfOmnivorousTextNode(RegExpCompiler *compiler)
static Smi * FromInt(int value)
#define LOG(isolate, Call)
void set_at_start(bool at_start)
GlobalCache(Handle< JSRegExp > regexp, Handle< String > subject, bool is_global, Isolate *isolate)
virtual void CheckNotBackReference(int start_reg, Label *on_no_match)=0
#define ASSERT_NOT_NULL(p)
struct v8::internal::ActionNode::@17::@20 u_position_register
bool EmitQuickCheck(RegExpCompiler *compiler, Trace *trace, bool preload_has_checked_bounds, Label *on_possible_success, QuickCheckDetails *details_return, bool fall_through_on_failure)
void set_loop_label(Label *label)
static Handle< T > cast(Handle< S > that)
static const int kJSRegexpStaticOffsetsVectorSize
static ActionNode * EmptyMatchCheck(int start_register, int repetition_register, int repetition_limit, RegExpNode *on_success)
virtual void ClearRegisters(int reg_from, int reg_to)=0
Position * positions(int index)
virtual RegExpNode * GetSuccessorOfOmnivorousTextNode(RegExpCompiler *compiler)
LimitResult LimitVersions(RegExpCompiler *compiler, Trace *trace)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static Handle< Object > CreateRegExpLiteral(Handle< JSFunction > constructor, Handle< String > pattern, Handle< String > flags, bool *has_pending_exception)
void AddFromFollowing(NodeInfo *that)
kSerializedDataOffset Object
void AddRange(CharacterRange range, int value, Zone *zone)
static ActionNode * IncrementRegister(int reg, RegExpNode *on_success)
static ByteArray * cast(Object *obj)
static int IrregexpNumberOfCaptures(FixedArray *re)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV 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 expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in only print modified registers Don t break for ASM_UNIMPLEMENTED_BREAK macros print stack trace when an illegal exception is thrown randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot testing_bool_flag testing_int_flag string flag tmp file in which to serialize heap Print the time it takes to lazily compile hydrogen code stubs concurrent_recompilation concurrent_sweeping Print usage message
static void EnsureSize(Handle< JSArray > array, int minimum_size_of_backing_fixed_array)
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
virtual void LoadCurrentCharacter(int cp_offset, Label *on_end_of_input, bool check_bounds=true, int characters=1)=0
static void Canonicalize(ZoneList< CharacterRange > *ranges)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
Handle< FixedArray > LookupRegExp(Handle< String > source, JSRegExp::Flags flags)
RegExpNode * FilterSuccessor(int depth, bool ignore_case)
void EnsureAnalyzed(RegExpNode *node)
void set_flush_budget(int to)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
static CharacterRange Everything()
virtual bool IsAnchoredAtEnd()
RegExpCompiler(int capture_count, bool ignore_case, bool is_ascii, Zone *zone)
virtual bool try_to_emit_quick_check_for_alternative(int i)
void AddValue(int value, Zone *zone)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
unibrow::Mapping< unibrow::Ecma262Canonicalize > Canonicalize
static uint16_t ConvertNonLatin1ToLatin1(uint16_t)
#define ASSERT(condition)
static ActionNode * StorePosition(int reg, bool is_capture, RegExpNode *on_success)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
int current_expansion_factor()
#define ASSERT_GE(v1, v2)
void set_characters_preloaded(int count)
const int kPatternTooShortForBoyerMoore
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler *compiler)
const char * error_message()
static const uint32_t kMaxOneByteCharCodeU
RegExpCompiler * compiler()
void BuildTable(ChoiceNode *node)
virtual void ReadCurrentPositionFromRegister(int reg)=0
bool EmitSkipInstructions(RegExpMacroAssembler *masm)
#define DEFINE_ACCEPT(Type)
ZoneList< TextElement > * elements()
void SetAll(int map_number)
virtual void PopCurrentPosition()=0
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
static Code * cast(Object *obj)
static void SetLastSubject(FixedArray *array, String *to)
struct v8::internal::ActionNode::@17::@21 u_submatch
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
static void Negate(ZoneList< CharacterRange > *src, ZoneList< CharacterRange > *dst, Zone *zone)
static Handle< Object > AtomExec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
static Smi * cast(Object *object)
Handle< String > FlattenGetString(Handle< String > string)
static const int kRegExpExecutableMemoryLimit
virtual void Emit(RegExpCompiler *compiler, Trace *trace)=0
static ActionNode * PositiveSubmatchSuccess(int stack_pointer_reg, int restore_reg, int clear_capture_count, int clear_capture_from, RegExpNode *on_success)
static const int kNoRegister
static const int kMaxExpansionFactor
virtual void AdvanceCurrentPosition(int by)=0
int get(uchar c, uchar n, uchar *result)
RegExpMacroAssembler * macro_assembler()
static void Split(ZoneList< CharacterRange > *base, Vector< const int > overlay, ZoneList< CharacterRange > **included, ZoneList< CharacterRange > **excluded, Zone *zone)
SmartArrayPointer< char > ToCString(AllowNullsFlag allow_nulls, RobustnessFlag robustness_flag, int offset, int length, int *length_output=0)
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
static void SetLastInput(FixedArray *array, String *to)
static const int kRegWxpCompiledLimit
void Advance(int by, bool ascii)
void Merge(QuickCheckDetails *other, int from_index)
void IncrementRecursionDepth()
virtual bool CanReadUnaligned()
RegExpExpansionLimiter(RegExpCompiler *compiler, int factor)
static int IrregexpPrepare(Handle< JSRegExp > regexp, Handle< String > subject)
void IncreaseTotalRegexpCodeGenerated(int size)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV 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_string(expose_natives_as
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static const int kRecursionBudget
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
static const unsigned kFirstLimit
void AddAlternative(GuardedAlternative node)
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
static void SetLastCaptureCount(FixedArray *array, int to)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV 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 expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in only print modified registers Don t break for ASM_UNIMPLEMENTED_BREAK macros print stack trace when an illegal exception is thrown randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot testing_bool_flag testing_int_flag string flag tmp file in which to serialize heap Print the time it takes to lazily compile hydrogen code stubs concurrent_recompilation concurrent_sweeping Print usage including flags
void fail(const char *error_message)
AlternativeGeneration * at(int i)
static void MemCopy(void *dest, const void *src, size_t size)
virtual void CheckCharacterGT(uc16 limit, Label *on_greater)=0
void Call(uc32 from, DispatchTable::Entry entry)
void set_bound_checked_up_to(int to)
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
void set_backtrack(Label *backtrack)
static const int kTableSizeBits
static const int kInfinity
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
virtual void Accept(NodeVisitor *visitor)
v8::Handle< v8::Object > bottom
static const int kTableSize
MemoryAllocator * memory_allocator()
void check(i::Vector< const uint8_t > string)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
void set_slow_safe(bool ssc)
void AddWork(RegExpNode *node)
static bool IsCanonical(ZoneList< CharacterRange > *ranges)
QuickCheckDetails * quick_check_performed()
static Handle< JSArray > SetLastMatchInfo(Handle< JSArray > last_match_info, Handle< String > subject, int capture_count, int32_t *match)
void AddGuard(Guard *guard, Zone *zone)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
void set_bm_info(bool not_at_start, BoyerMooreLookahead *bm)
void AddInverse(ZoneList< CharacterRange > *ranges)
virtual void VisitLoopChoice(LoopChoiceNode *that)
virtual int min_match()=0
void AddCaseEquivalents(ZoneList< CharacterRange > *ranges, bool is_ascii, Zone *zone)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
virtual void ReadStackPointerFromRegister(int reg)=0
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
static void IrregexpInitialize(Handle< JSRegExp > re, Handle< String > pattern, JSRegExp::Flags flags, int capture_register_count)
virtual void IfRegisterLT(int reg, int comparand, Label *if_lt)=0
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
virtual void CheckNotBackReferenceIgnoreCase(int start_reg, Label *on_no_match)=0
static const int kInOverlay
static RegExpImpl::IrregexpResult Match(Isolate *isolate, Handle< ByteArray > code, Handle< String > subject, int *captures, int start_position)
Handle< String > NewStringFromTwoByte(Vector< const uc16 > str, PretenureFlag pretenure=NOT_TENURED)
Handle< ByteArray > NewByteArray(int length, PretenureFlag pretenure=NOT_TENURED)
QuickCheckDetails quick_check_details
static Handle< Object > Exec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
Vector< const uc16 > ToUC16Vector()
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
static int IrregexpExecRaw(Handle< JSRegExp > regexp, Handle< String > subject, int index, int32_t *output, int output_size)
const int kMaxLookaheadForBoyerMoore
ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b)
static const int kMapSize
bool determines_perfectly
#define ASSERT_LE(v1, v2)
virtual void CheckNotAtStart(Label *on_not_at_start)=0
void add_action(DeferredAction *new_action)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
bool has_pending_exception()
BoyerMooreLookahead(int length, RegExpCompiler *compiler, Zone *zone)
virtual void CheckCharacter(unsigned c, Label *on_equal)=0
void SaveBMInfo(BoyerMooreLookahead *bm, bool not_at_start, int offset)
static const int kMaxRegister
static const int kIrregexpCaptureCountIndex
void AddRange(CharacterRange range)
void set_being_calculated(bool b)
static void AtomCompile(Handle< JSRegExp > re, Handle< String > pattern, JSRegExp::Flags flags, Handle< String > match_pattern)
int characters_preloaded()
DeferredAction * actions()
static const int kNodeIsTooComplexForGreedyLoops
void PutRegExp(Handle< String > source, JSRegExp::Flags flags, Handle< FixedArray > data)
Vector< const char > CStrVector(const char *data)
DispatchTable * GetTable(bool ignore_case)
static int IrregexpMaxRegisterCount(FixedArray *re)
int EatsAtLeastHelper(int still_to_find, int budget, RegExpNode *ignore_this_node, bool not_at_start)
void CountCharacter(int character)
RegExpNode * on_success()
static void SetIrregexpMaxRegisterCount(FixedArray *re, int value)
virtual void PushCurrentPosition()=0
static const int kTableMask
BoyerMooreLookahead * bm_info(bool not_at_start)
static int AtomExecRaw(Handle< JSRegExp > regexp, Handle< String > subject, int index, int32_t *output, int output_size)
#define ASSERT_LT(v1, v2)
virtual RegExpNode * FilterASCII(int depth, bool ignore_case)
static const int kLastMatchOverhead
~AlternativeGenerationList()
struct v8::internal::ActionNode::@17::@19 u_increment_register
void set_from(uc16 value)
FlatContent GetFlatContent()
int bound_checked_up_to()
intptr_t SizeExecutable()
virtual int GreedyLoopTextLength()
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
virtual bool CheckSpecialCharacterClass(uc16 type, Label *on_no_match)
static const int kMaxRecursion
void AddContinueAlternative(GuardedAlternative alt)
bool GetStoredPosition(int reg, int *cp_offset)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
static AssertionNode * AfterNewline(RegExpNode *on_success)
FrequencyCollator * frequency_collator()
void Sort(int(*cmp)(const T *x, const T *y))
static AssertionNode * AtNonBoundary(RegExpNode *on_success)
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset)=0
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function info
static const int kMaxWidth
virtual void VisitLoopChoice(LoopChoiceNode *that)
static const int kAtomPatternIndex
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
virtual void Bind(Label *label)=0
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)=0
int Count(int map_number)
void MakeCaseIndependent(bool is_ascii)
virtual void CheckCharacterLT(uc16 limit, Label *on_less)=0
ZoneList< GuardedAlternative > * alternatives()
virtual bool IsAnchoredAtStart()
static int code_index(bool is_ascii)
static void PrintError(const char *format,...)
void DecrementRecursionDepth()
static Handle< T > null()
int SearchString(Isolate *isolate, Vector< const SubjectChar > subject, Vector< const PatternChar > pattern, int start_index)
void SetRest(int from_map)
static Result Match(Handle< Code > regexp, Handle< String > subject, int *offsets_vector, int offsets_vector_length, int previous_index, Isolate *isolate)
virtual void Backtrack()=0
#define ASSERT_EQ(v1, v2)
void ForEach(Callback *callback)
virtual void AppendToText(RegExpText *text, Zone *zone)
OutSet * Extend(unsigned value, Zone *zone)
static void DotPrint(const char *label, RegExpNode *node, bool ignore_case)
static const uchar kBadChar
struct v8::internal::ActionNode::@17::@18 u_store_register
StringCharacterStream *const stream_
ZoneList< GuardedAlternative > * alternatives_
virtual void CheckCharacterAfterAnd(unsigned c, unsigned and_with, Label *on_equal)=0
ContainedInLattice AddRange(ContainedInLattice containment, const int *ranges, int ranges_length, Interval new_range)
virtual void IfRegisterEqPos(int reg, Label *if_eq)=0
virtual int GreedyLoopTextLength()
static ByteArray * IrregexpByteCode(FixedArray *re, bool is_ascii)
static FixedArray * cast(Object *obj)
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
void set_current_expansion_factor(int value)
static ActionNode * ClearCaptures(Interval range, RegExpNode *on_success)
void Set(int map_number, int character)
static int IrregexpNumberOfRegisters(FixedArray *re)
virtual void CheckBitInTable(Handle< ByteArray > table, Label *on_bit_set)=0
unibrow::Mapping< unibrow::CanonicalizationRange > * jsregexp_canonrange()
static const int kCompilationErrorValue
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
bool Rationalize(bool ascii)
virtual void CheckGreedyLoop(Label *on_tos_equals_current_position)=0
void AddLoopAlternative(GuardedAlternative alt)
void set_choice_index(int value)
virtual void Accept(NodeVisitor *visitor)=0
static Handle< Object > Compile(Handle< JSRegExp > re, Handle< String > pattern, Handle< String > flags)
ActionNode::ActionType action_type()
ZoneList< Guard * > * guards()
virtual void Emit(RegExpCompiler *compiler, Trace *trace)
static Handle< Object > IrregexpExec(Handle< JSRegExp > regexp, Handle< String > subject, int index, Handle< JSArray > lastMatchInfo)
#define FOR_EACH_NODE_TYPE(VISIT)
Vector< const uint8_t > ToOneByteVector()
void Call(uc16 from, DispatchTable::Entry entry)
virtual int max_match()=0
~RegExpExpansionLimiter()
void Flush(RegExpCompiler *compiler, RegExpNode *successor)
static const int kUninitializedValue
void set_quick_check_performed(QuickCheckDetails *d)
struct v8::internal::ActionNode::@17::@23 u_clear_captures
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV 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 expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
void InvalidateCurrentCharacter()
virtual void CheckNotCharacter(unsigned c, Label *on_not_equal)=0
static void AddClassEscape(uc16 type, ZoneList< CharacterRange > *ranges, Zone *zone)
static int saved_code_index(bool is_ascii)
static const int32_t kMaxOneByteCharCode
int Frequency(int in_character)
virtual void CheckPosition(int cp_offset, Label *on_outside_input)
virtual void FillInBMInfo(int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
RecursionCheck(RegExpCompiler *compiler)
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)=0
static CharacterRange Singleton(uc16 value)
static AssertionNode * AtEnd(RegExpNode *on_success)
virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, Label *on_not_equal)=0
virtual Handle< HeapObject > GetCode(Handle< String > source)=0
AddDispatchRange(DispatchTableConstructor *constructor)
virtual void GetQuickCheckDetails(QuickCheckDetails *details, RegExpCompiler *compiler, int filled_in, bool not_at_start)
virtual void IfRegisterGE(int reg, int comparand, Label *if_ge)=0
void set_stop_node(RegExpNode *node)
virtual void PushBacktrack(Label *label)=0
static CompilationResult Compile(RegExpCompileData *input, bool ignore_case, bool global, bool multiline, Handle< String > pattern, Handle< String > sample_subject, bool is_ascii, Zone *zone)
static void SetCapture(FixedArray *array, int index, int to)
static AssertionNode * AtBoundary(RegExpNode *on_success)
bool mentions_reg(int reg)
static const int kMaxCPOffset