| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 class OffsetsVector { | 207 class OffsetsVector { |
| 208 public: | 208 public: |
| 209 inline OffsetsVector(int num_registers) | 209 inline OffsetsVector(int num_registers) |
| 210 : offsets_vector_length_(num_registers) { | 210 : offsets_vector_length_(num_registers) { |
| 211 if (offsets_vector_length_ > kStaticOffsetsVectorSize) { | 211 if (offsets_vector_length_ > kStaticOffsetsVectorSize) { |
| 212 vector_ = NewArray<int>(offsets_vector_length_); | 212 vector_ = NewArray<int>(offsets_vector_length_); |
| 213 } else { | 213 } else { |
| 214 vector_ = static_offsets_vector_; | 214 vector_ = static_offsets_vector_; |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 | |
| 218 | |
| 219 inline ~OffsetsVector() { | 217 inline ~OffsetsVector() { |
| 220 if (offsets_vector_length_ > kStaticOffsetsVectorSize) { | 218 if (offsets_vector_length_ > kStaticOffsetsVectorSize) { |
| 221 DeleteArray(vector_); | 219 DeleteArray(vector_); |
| 222 vector_ = NULL; | 220 vector_ = NULL; |
| 223 } | 221 } |
| 224 } | 222 } |
| 225 | 223 inline int* vector() { return vector_; } |
| 226 | 224 inline int length() { return offsets_vector_length_; } |
| 227 inline int* vector() { | |
| 228 return vector_; | |
| 229 } | |
| 230 | |
| 231 | |
| 232 inline int length() { | |
| 233 return offsets_vector_length_; | |
| 234 } | |
| 235 | 225 |
| 236 private: | 226 private: |
| 237 int* vector_; | 227 int* vector_; |
| 238 int offsets_vector_length_; | 228 int offsets_vector_length_; |
| 239 static const int kStaticOffsetsVectorSize = 50; | 229 static const int kStaticOffsetsVectorSize = 50; |
| 240 static int static_offsets_vector_[kStaticOffsetsVectorSize]; | 230 static int static_offsets_vector_[kStaticOffsetsVectorSize]; |
| 241 }; | 231 }; |
| 242 | 232 |
| 243 | 233 |
| 244 int OffsetsVector::static_offsets_vector_[ | 234 int OffsetsVector::static_offsets_vector_[ |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 int previous_index = static_cast<int>(DoubleToInteger(index->Number())); | 786 int previous_index = static_cast<int>(DoubleToInteger(index->Number())); |
| 797 | 787 |
| 798 #ifdef DEBUG | 788 #ifdef DEBUG |
| 799 if (FLAG_trace_regexp_bytecodes) { | 789 if (FLAG_trace_regexp_bytecodes) { |
| 800 String* pattern = regexp->Pattern(); | 790 String* pattern = regexp->Pattern(); |
| 801 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); | 791 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); |
| 802 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); | 792 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); |
| 803 } | 793 } |
| 804 #endif | 794 #endif |
| 805 LOG(RegExpExecEvent(regexp, previous_index, subject)); | 795 LOG(RegExpExecEvent(regexp, previous_index, subject)); |
| 796 |
| 797 if (!subject->IsFlat(StringShape(*subject))) { |
| 798 FlattenString(subject); |
| 799 } |
| 800 |
| 806 return IrregexpExecOnce(irregexp, | 801 return IrregexpExecOnce(irregexp, |
| 807 num_captures, | 802 num_captures, |
| 808 subject, | 803 subject, |
| 809 previous_index, | 804 previous_index, |
| 810 offsets.vector(), | 805 offsets.vector(), |
| 811 offsets.length()); | 806 offsets.length()); |
| 812 } | 807 } |
| 813 | 808 |
| 814 | 809 |
| 815 Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp, | 810 Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 830 int previous_index = 0; | 825 int previous_index = 0; |
| 831 | 826 |
| 832 Handle<JSArray> result = Factory::NewJSArray(0); | 827 Handle<JSArray> result = Factory::NewJSArray(0); |
| 833 int i = 0; | 828 int i = 0; |
| 834 Handle<Object> matches; | 829 Handle<Object> matches; |
| 835 | 830 |
| 836 if (!subject->IsFlat(shape)) { | 831 if (!subject->IsFlat(shape)) { |
| 837 subject->Flatten(shape); | 832 subject->Flatten(shape); |
| 838 } | 833 } |
| 839 | 834 |
| 840 do { | 835 while (true) { |
| 841 if (previous_index > subject->length() || previous_index < 0) { | 836 if (previous_index > subject->length() || previous_index < 0) { |
| 842 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | 837 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 843 // string length, there is no match. | 838 // string length, there is no match. |
| 844 matches = Factory::null_value(); | 839 matches = Factory::null_value(); |
| 840 return result; |
| 845 } else { | 841 } else { |
| 846 #ifdef DEBUG | 842 #ifdef DEBUG |
| 847 if (FLAG_trace_regexp_bytecodes) { | 843 if (FLAG_trace_regexp_bytecodes) { |
| 848 String* pattern = regexp->Pattern(); | 844 String* pattern = regexp->Pattern(); |
| 849 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); | 845 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); |
| 850 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); | 846 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); |
| 851 } | 847 } |
| 852 #endif | 848 #endif |
| 853 LOG(RegExpExecEvent(regexp, previous_index, subject)); | 849 LOG(RegExpExecEvent(regexp, previous_index, subject)); |
| 854 matches = IrregexpExecOnce(irregexp, | 850 matches = IrregexpExecOnce(irregexp, |
| 855 IrregexpNumberOfCaptures(irregexp), | 851 IrregexpNumberOfCaptures(irregexp), |
| 856 subject, | 852 subject, |
| 857 previous_index, | 853 previous_index, |
| 858 offsets.vector(), | 854 offsets.vector(), |
| 859 offsets.length()); | 855 offsets.length()); |
| 860 | 856 |
| 861 if (matches->IsJSArray()) { | 857 if (matches->IsJSArray()) { |
| 862 SetElement(result, i, matches); | 858 SetElement(result, i, matches); |
| 863 i++; | 859 i++; |
| 864 previous_index = offsets.vector()[1]; | 860 previous_index = offsets.vector()[1]; |
| 865 if (offsets.vector()[0] == offsets.vector()[1]) { | 861 if (offsets.vector()[0] == offsets.vector()[1]) { |
| 866 previous_index++; | 862 previous_index++; |
| 867 } | 863 } |
| 864 } else if (matches->IsNull()) { |
| 865 return result; |
| 866 } else { |
| 867 return matches; |
| 868 } | 868 } |
| 869 } | 869 } |
| 870 } while (matches->IsJSArray()); | |
| 871 | |
| 872 // If we exited the loop with an exception, throw it. | |
| 873 if (matches->IsNull()) { | |
| 874 // Exited loop normally. | |
| 875 return result; | |
| 876 } else { | |
| 877 // Exited loop with the exception in matches. | |
| 878 return matches; | |
| 879 } | 870 } |
| 880 } | 871 } |
| 881 | 872 |
| 882 | 873 |
| 883 Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp, | 874 Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp, |
| 884 int num_captures, | 875 int num_captures, |
| 885 Handle<String> subject, | 876 Handle<String> subject, |
| 886 int previous_index, | 877 int previous_index, |
| 887 int* offsets_vector, | 878 int* offsets_vector, |
| 888 int offsets_vector_length) { | 879 int offsets_vector_length) { |
| 880 ASSERT(subject->IsFlat(StringShape(*subject))); |
| 889 bool rc; | 881 bool rc; |
| 890 | 882 |
| 891 int tag = Smi::cast(irregexp->get(kIrregexpImplementationIndex))->value(); | 883 int tag = Smi::cast(irregexp->get(kIrregexpImplementationIndex))->value(); |
| 892 | 884 |
| 893 if (!subject->IsFlat(StringShape(*subject))) { | |
| 894 FlattenString(subject); | |
| 895 } | |
| 896 | |
| 897 switch (tag) { | 885 switch (tag) { |
| 898 case RegExpMacroAssembler::kIA32Implementation: { | 886 case RegExpMacroAssembler::kIA32Implementation: { |
| 899 #ifndef ARM | 887 #ifndef ARM |
| 900 Handle<Code> code = IrregexpNativeCode(irregexp); | 888 Handle<Code> code = IrregexpNativeCode(irregexp); |
| 901 | 889 |
| 902 StringShape shape(*subject); | 890 StringShape shape(*subject); |
| 903 | 891 |
| 904 // Character offsets into string. | 892 // Character offsets into string. |
| 905 int start_offset = previous_index; | 893 int start_offset = previous_index; |
| 906 int end_offset = subject->length(shape); | 894 int end_offset = subject->length(shape); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 rc = false; | 978 rc = false; |
| 991 break; | 979 break; |
| 992 } | 980 } |
| 993 | 981 |
| 994 if (!rc) { | 982 if (!rc) { |
| 995 return Factory::null_value(); | 983 return Factory::null_value(); |
| 996 } | 984 } |
| 997 | 985 |
| 998 Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1)); | 986 Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1)); |
| 999 // The captures come in (start, end+1) pairs. | 987 // The captures come in (start, end+1) pairs. |
| 1000 for (int i = 0; i < 2 * (num_captures+1); i += 2) { | 988 for (int i = 0; i < 2 * (num_captures + 1); i += 2) { |
| 1001 array->set(i, Smi::FromInt(offsets_vector[i])); | 989 array->set(i, Smi::FromInt(offsets_vector[i])); |
| 1002 array->set(i+1, Smi::FromInt(offsets_vector[i+1])); | 990 array->set(i + 1, Smi::FromInt(offsets_vector[i + 1])); |
| 1003 } | 991 } |
| 1004 return Factory::NewJSArrayWithElements(array); | 992 return Factory::NewJSArrayWithElements(array); |
| 1005 } | 993 } |
| 1006 | 994 |
| 1007 | 995 |
| 1008 // ------------------------------------------------------------------- | 996 // ------------------------------------------------------------------- |
| 1009 // Implmentation of the Irregexp regular expression engine. | 997 // Implmentation of the Irregexp regular expression engine. |
| 1010 // | 998 // |
| 1011 // The Irregexp regular expression engine is intended to be a complete | 999 // The Irregexp regular expression engine is intended to be a complete |
| 1012 // implementation of ECMAScript regular expressions. It generates either | 1000 // implementation of ECMAScript regular expressions. It generates either |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 | 1174 |
| 1187 | 1175 |
| 1188 TextElement TextElement::CharClass( | 1176 TextElement TextElement::CharClass( |
| 1189 RegExpCharacterClass* char_class) { | 1177 RegExpCharacterClass* char_class) { |
| 1190 TextElement result = TextElement(CHAR_CLASS); | 1178 TextElement result = TextElement(CHAR_CLASS); |
| 1191 result.data.u_char_class = char_class; | 1179 result.data.u_char_class = char_class; |
| 1192 return result; | 1180 return result; |
| 1193 } | 1181 } |
| 1194 | 1182 |
| 1195 | 1183 |
| 1184 int TextElement::length() { |
| 1185 if (type == ATOM) { |
| 1186 return data.u_atom->length(); |
| 1187 } else { |
| 1188 ASSERT(type == CHAR_CLASS); |
| 1189 return 1; |
| 1190 } |
| 1191 } |
| 1192 |
| 1193 |
| 1196 DispatchTable* ChoiceNode::GetTable(bool ignore_case) { | 1194 DispatchTable* ChoiceNode::GetTable(bool ignore_case) { |
| 1197 if (table_ == NULL) { | 1195 if (table_ == NULL) { |
| 1198 table_ = new DispatchTable(); | 1196 table_ = new DispatchTable(); |
| 1199 DispatchTableConstructor cons(table_, ignore_case); | 1197 DispatchTableConstructor cons(table_, ignore_case); |
| 1200 cons.BuildTable(this); | 1198 cons.BuildTable(this); |
| 1201 } | 1199 } |
| 1202 return table_; | 1200 return table_; |
| 1203 } | 1201 } |
| 1204 | 1202 |
| 1205 | 1203 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1327 for (DeferredAction* action = actions_; | 1325 for (DeferredAction* action = actions_; |
| 1328 action != NULL; | 1326 action != NULL; |
| 1329 action = action->next()) { | 1327 action = action->next()) { |
| 1330 affected_registers->Set(action->reg()); | 1328 affected_registers->Set(action->reg()); |
| 1331 if (action->reg() > max_register) max_register = action->reg(); | 1329 if (action->reg() > max_register) max_register = action->reg(); |
| 1332 } | 1330 } |
| 1333 return max_register; | 1331 return max_register; |
| 1334 } | 1332 } |
| 1335 | 1333 |
| 1336 | 1334 |
| 1337 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* macro, | 1335 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler, |
| 1338 int max_register, | 1336 int max_register, |
| 1339 OutSet& affected_registers) { | 1337 OutSet& affected_registers) { |
| 1340 for (int reg = 0; reg <= max_register; reg++) { | 1338 for (int reg = 0; reg <= max_register; reg++) { |
| 1341 if (affected_registers.Get(reg)) macro->PushRegister(reg); | 1339 if (affected_registers.Get(reg)) assembler->PushRegister(reg); |
| 1342 } | 1340 } |
| 1343 } | 1341 } |
| 1344 | 1342 |
| 1345 | 1343 |
| 1346 void GenerationVariant::RestoreAffectedRegisters(RegExpMacroAssembler* macro, | 1344 void GenerationVariant::RestoreAffectedRegisters( |
| 1347 int max_register, | 1345 RegExpMacroAssembler* assembler, |
| 1348 OutSet& affected_registers) { | 1346 int max_register, |
| 1347 OutSet& affected_registers) { |
| 1349 for (int reg = max_register; reg >= 0; reg--) { | 1348 for (int reg = max_register; reg >= 0; reg--) { |
| 1350 if (affected_registers.Get(reg)) macro->PopRegister(reg); | 1349 if (affected_registers.Get(reg)) assembler->PopRegister(reg); |
| 1351 } | 1350 } |
| 1352 } | 1351 } |
| 1353 | 1352 |
| 1354 | 1353 |
| 1355 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* macro, | 1354 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* assembler, |
| 1356 int max_register, | 1355 int max_register, |
| 1357 OutSet& affected_registers) { | 1356 OutSet& affected_registers) { |
| 1358 for (int reg = 0; reg <= max_register; reg++) { | 1357 for (int reg = 0; reg <= max_register; reg++) { |
| 1359 if (!affected_registers.Get(reg)) { | 1358 if (!affected_registers.Get(reg)) { |
| 1360 continue; | 1359 continue; |
| 1361 } | 1360 } |
| 1362 int value = 0; | 1361 int value = 0; |
| 1363 bool absolute = false; | 1362 bool absolute = false; |
| 1364 int store_position = -1; | 1363 int store_position = -1; |
| 1365 // This is a little tricky because we are scanning the actions in reverse | 1364 // This is a little tricky because we are scanning the actions in reverse |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1393 ASSERT_EQ(value, 0); | 1392 ASSERT_EQ(value, 0); |
| 1394 break; | 1393 break; |
| 1395 } | 1394 } |
| 1396 default: | 1395 default: |
| 1397 UNREACHABLE(); | 1396 UNREACHABLE(); |
| 1398 break; | 1397 break; |
| 1399 } | 1398 } |
| 1400 } | 1399 } |
| 1401 } | 1400 } |
| 1402 if (store_position != -1) { | 1401 if (store_position != -1) { |
| 1403 macro->WriteCurrentPositionToRegister(reg, store_position); | 1402 assembler->WriteCurrentPositionToRegister(reg, store_position); |
| 1404 } else { | 1403 } else { |
| 1405 if (absolute) { | 1404 if (absolute) { |
| 1406 macro->SetRegister(reg, value); | 1405 assembler->SetRegister(reg, value); |
| 1407 } else { | 1406 } else { |
| 1408 if (value != 0) { | 1407 if (value != 0) { |
| 1409 macro->AdvanceRegister(reg, value); | 1408 assembler->AdvanceRegister(reg, value); |
| 1410 } | 1409 } |
| 1411 } | 1410 } |
| 1412 } | 1411 } |
| 1413 } | 1412 } |
| 1414 } | 1413 } |
| 1415 | 1414 |
| 1416 | 1415 |
| 1417 // This is called as we come into a loop choice node and some other tricky | 1416 // This is called as we come into a loop choice node and some other tricky |
| 1418 // nodes. It normalises the state of the code generator to ensure we can | 1417 // nodes. It normalises the state of the code generator to ensure we can |
| 1419 // generate generic code. | 1418 // generate generic code. |
| 1420 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) { | 1419 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
| 1421 RegExpMacroAssembler* macro = compiler->macro_assembler(); | 1420 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1422 | 1421 |
| 1423 ASSERT(actions_ != NULL || cp_offset_ != 0 || backtrack() != NULL); | 1422 ASSERT(actions_ != NULL || |
| 1423 cp_offset_ != 0 || |
| 1424 backtrack() != NULL || |
| 1425 characters_preloaded_ != 0 || |
| 1426 quick_check_performed_.characters() != 0); |
| 1424 | 1427 |
| 1425 if (actions_ == NULL && backtrack() == NULL) { | 1428 if (actions_ == NULL && backtrack() == NULL) { |
| 1426 // Here we just have some deferred cp advances to fix and we are back to | 1429 // Here we just have some deferred cp advances to fix and we are back to |
| 1427 // a normal situation. | 1430 // a normal situation. We may also have to forget some information gained |
| 1428 macro->AdvanceCurrentPosition(cp_offset_); | 1431 // through a quick check that was already performed. |
| 1432 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); |
| 1429 // Create a new trivial state and generate the node with that. | 1433 // Create a new trivial state and generate the node with that. |
| 1430 GenerationVariant new_state; | 1434 GenerationVariant new_state; |
| 1431 return successor->Emit(compiler, &new_state); | 1435 return successor->Emit(compiler, &new_state); |
| 1432 } | 1436 } |
| 1433 | 1437 |
| 1434 // Generate deferred actions here along with code to undo them again. | 1438 // Generate deferred actions here along with code to undo them again. |
| 1435 OutSet affected_registers; | 1439 OutSet affected_registers; |
| 1436 int max_register = FindAffectedRegisters(&affected_registers); | 1440 int max_register = FindAffectedRegisters(&affected_registers); |
| 1437 PushAffectedRegisters(macro, max_register, affected_registers); | 1441 PushAffectedRegisters(assembler, max_register, affected_registers); |
| 1438 PerformDeferredActions(macro, max_register, affected_registers); | 1442 PerformDeferredActions(assembler, max_register, affected_registers); |
| 1439 if (backtrack() != NULL) { | 1443 if (backtrack() != NULL) { |
| 1440 // Here we have a concrete backtrack location. These are set up by choice | 1444 // Here we have a concrete backtrack location. These are set up by choice |
| 1441 // nodes and so they indicate that we have a deferred save of the current | 1445 // nodes and so they indicate that we have a deferred save of the current |
| 1442 // position which we may need to emit here. | 1446 // position which we may need to emit here. |
| 1443 macro->PushCurrentPosition(); | 1447 assembler->PushCurrentPosition(); |
| 1444 } | 1448 } |
| 1445 if (cp_offset_ != 0) { | 1449 if (cp_offset_ != 0) { |
| 1446 macro->AdvanceCurrentPosition(cp_offset_); | 1450 assembler->AdvanceCurrentPosition(cp_offset_); |
| 1447 } | 1451 } |
| 1448 | 1452 |
| 1449 // Create a new trivial state and generate the node with that. | 1453 // Create a new trivial state and generate the node with that. |
| 1450 Label undo; | 1454 Label undo; |
| 1451 macro->PushBacktrack(&undo); | 1455 assembler->PushBacktrack(&undo); |
| 1452 GenerationVariant new_state; | 1456 GenerationVariant new_state; |
| 1453 bool ok = successor->Emit(compiler, &new_state); | 1457 bool ok = successor->Emit(compiler, &new_state); |
| 1454 | 1458 |
| 1455 // On backtrack we need to restore state. | 1459 // On backtrack we need to restore state. |
| 1456 macro->Bind(&undo); | 1460 assembler->Bind(&undo); |
| 1457 if (!ok) return false; | 1461 if (!ok) return false; |
| 1458 if (backtrack() != NULL) { | 1462 if (backtrack() != NULL) { |
| 1459 macro->PopCurrentPosition(); | 1463 assembler->PopCurrentPosition(); |
| 1460 } | 1464 } |
| 1461 RestoreAffectedRegisters(macro, max_register, affected_registers); | 1465 RestoreAffectedRegisters(assembler, max_register, affected_registers); |
| 1462 if (backtrack() == NULL) { | 1466 if (backtrack() == NULL) { |
| 1463 macro->Backtrack(); | 1467 assembler->Backtrack(); |
| 1464 } else { | 1468 } else { |
| 1465 macro->GoTo(backtrack()); | 1469 assembler->GoTo(backtrack()); |
| 1466 } | 1470 } |
| 1467 | 1471 |
| 1468 return true; | 1472 return true; |
| 1469 } | 1473 } |
| 1470 | 1474 |
| 1471 | 1475 |
| 1472 void EndNode::EmitInfoChecks(RegExpMacroAssembler* macro, | 1476 void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, |
| 1473 GenerationVariant* variant) { | 1477 GenerationVariant* variant) { |
| 1474 if (info()->at_end) { | 1478 if (info()->at_end) { |
| 1475 Label succeed; | 1479 Label succeed; |
| 1476 // LoadCurrentCharacter will go to the label if we are at the end of the | 1480 // LoadCurrentCharacter will go to the label if we are at the end of the |
| 1477 // input string. | 1481 // input string. |
| 1478 macro->LoadCurrentCharacter(0, &succeed); | 1482 assembler->LoadCurrentCharacter(0, &succeed); |
| 1479 macro->GoTo(variant->backtrack()); | 1483 assembler->GoTo(variant->backtrack()); |
| 1480 macro->Bind(&succeed); | 1484 assembler->Bind(&succeed); |
| 1481 } | 1485 } |
| 1482 } | 1486 } |
| 1483 | 1487 |
| 1484 | 1488 |
| 1485 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, | 1489 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, |
| 1486 GenerationVariant* variant) { | 1490 GenerationVariant* variant) { |
| 1487 if (!variant->is_trivial()) { | 1491 if (!variant->is_trivial()) { |
| 1488 return variant->Flush(compiler, this); | 1492 return variant->Flush(compiler, this); |
| 1489 } | 1493 } |
| 1490 RegExpMacroAssembler* macro = compiler->macro_assembler(); | 1494 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1491 if (!label()->is_bound()) { | 1495 if (!label()->is_bound()) { |
| 1492 macro->Bind(label()); | 1496 assembler->Bind(label()); |
| 1493 } | 1497 } |
| 1494 EmitInfoChecks(macro, variant); | 1498 EmitInfoChecks(assembler, variant); |
| 1495 macro->ReadCurrentPositionFromRegister(current_position_register_); | 1499 assembler->ReadCurrentPositionFromRegister(current_position_register_); |
| 1496 macro->ReadStackPointerFromRegister(stack_pointer_register_); | 1500 assembler->ReadStackPointerFromRegister(stack_pointer_register_); |
| 1497 // Now that we have unwound the stack we find at the top of the stack the | 1501 // Now that we have unwound the stack we find at the top of the stack the |
| 1498 // backtrack that the BeginSubmatch node got. | 1502 // backtrack that the BeginSubmatch node got. |
| 1499 macro->Backtrack(); | 1503 assembler->Backtrack(); |
| 1500 return true; | 1504 return true; |
| 1501 } | 1505 } |
| 1502 | 1506 |
| 1503 | 1507 |
| 1504 bool EndNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 1508 bool EndNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { |
| 1505 if (!variant->is_trivial()) { | 1509 if (!variant->is_trivial()) { |
| 1506 return variant->Flush(compiler, this); | 1510 return variant->Flush(compiler, this); |
| 1507 } | 1511 } |
| 1508 RegExpMacroAssembler* macro = compiler->macro_assembler(); | 1512 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1509 if (!label()->is_bound()) { | 1513 if (!label()->is_bound()) { |
| 1510 macro->Bind(label()); | 1514 assembler->Bind(label()); |
| 1511 } | 1515 } |
| 1512 switch (action_) { | 1516 switch (action_) { |
| 1513 case ACCEPT: | 1517 case ACCEPT: |
| 1514 EmitInfoChecks(macro, variant); | 1518 EmitInfoChecks(assembler, variant); |
| 1515 macro->Succeed(); | 1519 assembler->Succeed(); |
| 1516 return true; | 1520 return true; |
| 1517 case BACKTRACK: | 1521 case BACKTRACK: |
| 1518 ASSERT(!info()->at_end); | 1522 ASSERT(!info()->at_end); |
| 1519 macro->GoTo(variant->backtrack()); | 1523 assembler->GoTo(variant->backtrack()); |
| 1520 return true; | 1524 return true; |
| 1521 case NEGATIVE_SUBMATCH_SUCCESS: | 1525 case NEGATIVE_SUBMATCH_SUCCESS: |
| 1522 // This case is handled in a different virtual method. | 1526 // This case is handled in a different virtual method. |
| 1523 UNREACHABLE(); | 1527 UNREACHABLE(); |
| 1524 } | 1528 } |
| 1525 UNIMPLEMENTED(); | 1529 UNIMPLEMENTED(); |
| 1526 return false; | 1530 return false; |
| 1527 } | 1531 } |
| 1528 | 1532 |
| 1529 | 1533 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1579 | 1583 |
| 1580 | 1584 |
| 1581 #define DEFINE_ACCEPT(Type) \ | 1585 #define DEFINE_ACCEPT(Type) \ |
| 1582 void Type##Node::Accept(NodeVisitor* visitor) { \ | 1586 void Type##Node::Accept(NodeVisitor* visitor) { \ |
| 1583 visitor->Visit##Type(this); \ | 1587 visitor->Visit##Type(this); \ |
| 1584 } | 1588 } |
| 1585 FOR_EACH_NODE_TYPE(DEFINE_ACCEPT) | 1589 FOR_EACH_NODE_TYPE(DEFINE_ACCEPT) |
| 1586 #undef DEFINE_ACCEPT | 1590 #undef DEFINE_ACCEPT |
| 1587 | 1591 |
| 1588 | 1592 |
| 1593 void LoopChoiceNode::Accept(NodeVisitor* visitor) { |
| 1594 visitor->VisitLoopChoice(this); |
| 1595 } |
| 1596 |
| 1597 |
| 1589 // ------------------------------------------------------------------- | 1598 // ------------------------------------------------------------------- |
| 1590 // Emit code. | 1599 // Emit code. |
| 1591 | 1600 |
| 1592 | 1601 |
| 1593 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, | 1602 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 1594 Guard* guard, | 1603 Guard* guard, |
| 1595 GenerationVariant* variant) { | 1604 GenerationVariant* variant) { |
| 1596 switch (guard->op()) { | 1605 switch (guard->op()) { |
| 1597 case Guard::LT: | 1606 case Guard::LT: |
| 1598 ASSERT(!variant->mentions_reg(guard->reg())); | 1607 ASSERT(!variant->mentions_reg(guard->reg())); |
| 1599 macro_assembler->IfRegisterGE(guard->reg(), | 1608 macro_assembler->IfRegisterGE(guard->reg(), |
| 1600 guard->value(), | 1609 guard->value(), |
| 1601 variant->backtrack()); | 1610 variant->backtrack()); |
| 1602 break; | 1611 break; |
| 1603 case Guard::GEQ: | 1612 case Guard::GEQ: |
| 1604 ASSERT(!variant->mentions_reg(guard->reg())); | 1613 ASSERT(!variant->mentions_reg(guard->reg())); |
| 1605 macro_assembler->IfRegisterLT(guard->reg(), | 1614 macro_assembler->IfRegisterLT(guard->reg(), |
| 1606 guard->value(), | 1615 guard->value(), |
| 1607 variant->backtrack()); | 1616 variant->backtrack()); |
| 1608 break; | 1617 break; |
| 1609 } | 1618 } |
| 1610 } | 1619 } |
| 1611 | 1620 |
| 1612 | 1621 |
| 1613 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; | 1622 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; |
| 1614 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; | 1623 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; |
| 1615 | 1624 |
| 1616 | 1625 |
| 1617 static inline void EmitAtomNonLetters( | 1626 // Only emits non-letters (things that don't have case). Only used for case |
| 1627 // independent matches. |
| 1628 static inline bool EmitAtomNonLetter( |
| 1618 RegExpMacroAssembler* macro_assembler, | 1629 RegExpMacroAssembler* macro_assembler, |
| 1619 TextElement elm, | 1630 uc16 c, |
| 1620 Vector<const uc16> quarks, | |
| 1621 Label* on_failure, | 1631 Label* on_failure, |
| 1622 int cp_offset, | 1632 int cp_offset, |
| 1623 bool check_offset) { | 1633 bool check, |
| 1634 bool preloaded) { |
| 1624 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 1635 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 1625 // It is vital that this loop is backwards due to the unchecked character | 1636 int length = uncanonicalize.get(c, '\0', chars); |
| 1626 // load below. | 1637 bool checked = false; |
| 1627 for (int i = quarks.length() - 1; i >= 0; i--) { | 1638 if (length <= 1) { |
| 1628 uc16 c = quarks[i]; | 1639 if (!preloaded) { |
| 1629 int length = uncanonicalize.get(c, '\0', chars); | 1640 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check); |
| 1630 if (length <= 1) { | 1641 checked = check; |
| 1631 if (check_offset && i == quarks.length() - 1) { | |
| 1632 macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure); | |
| 1633 } else { | |
| 1634 // Here we don't need to check against the end of the input string | |
| 1635 // since this character lies before a character that matched. | |
| 1636 macro_assembler->LoadCurrentCharacterUnchecked(cp_offset + i); | |
| 1637 } | |
| 1638 macro_assembler->CheckNotCharacter(c, on_failure); | |
| 1639 } | 1642 } |
| 1643 macro_assembler->CheckNotCharacter(c, on_failure); |
| 1640 } | 1644 } |
| 1645 return checked; |
| 1641 } | 1646 } |
| 1642 | 1647 |
| 1643 | 1648 |
| 1644 static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler, | 1649 static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler, |
| 1645 uc16 c1, | 1650 uc16 c1, |
| 1646 uc16 c2, | 1651 uc16 c2, |
| 1647 Label* on_failure) { | 1652 Label* on_failure) { |
| 1648 uc16 exor = c1 ^ c2; | 1653 uc16 exor = c1 ^ c2; |
| 1649 // Check whether exor has only one bit set. | 1654 // Check whether exor has only one bit set. |
| 1650 if (((exor - 1) & exor) == 0) { | 1655 if (((exor - 1) & exor) == 0) { |
| 1651 // If c1 and c2 differ only by one bit. | 1656 // If c1 and c2 differ only by one bit. |
| 1652 // Ecma262UnCanonicalize always gives the highest number last. | 1657 // Ecma262UnCanonicalize always gives the highest number last. |
| 1653 ASSERT(c2 > c1); | 1658 ASSERT(c2 > c1); |
| 1654 macro_assembler->CheckNotCharacterAfterOr(c2, exor, on_failure); | 1659 uc16 mask = String::kMaxUC16CharCode ^ exor; |
| 1660 macro_assembler->CheckNotCharacterAfterAnd(c1, mask, on_failure); |
| 1655 return true; | 1661 return true; |
| 1656 } | 1662 } |
| 1657 ASSERT(c2 > c1); | 1663 ASSERT(c2 > c1); |
| 1658 uc16 diff = c2 - c1; | 1664 uc16 diff = c2 - c1; |
| 1659 if (((diff - 1) & diff) == 0 && c1 >= diff) { | 1665 if (((diff - 1) & diff) == 0 && c1 >= diff) { |
| 1660 // If the characters differ by 2^n but don't differ by one bit then | 1666 // If the characters differ by 2^n but don't differ by one bit then |
| 1661 // subtract the difference from the found character, then do the or | 1667 // subtract the difference from the found character, then do the or |
| 1662 // trick. We avoid the theoretical case where negative numbers are | 1668 // trick. We avoid the theoretical case where negative numbers are |
| 1663 // involved in order to simplify code generation. | 1669 // involved in order to simplify code generation. |
| 1664 macro_assembler->CheckNotCharacterAfterMinusOr(c2 - diff, | 1670 uc16 mask = String::kMaxUC16CharCode ^ diff; |
| 1665 diff, | 1671 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff, |
| 1666 on_failure); | 1672 diff, |
| 1673 mask, |
| 1674 on_failure); |
| 1667 return true; | 1675 return true; |
| 1668 } | 1676 } |
| 1669 return false; | 1677 return false; |
| 1670 } | 1678 } |
| 1671 | 1679 |
| 1672 | 1680 |
| 1673 static inline void EmitAtomLetters( | 1681 // Only emits letters (things that have case). Only used for case independent |
| 1682 // matches. |
| 1683 static inline bool EmitAtomLetter( |
| 1674 RegExpMacroAssembler* macro_assembler, | 1684 RegExpMacroAssembler* macro_assembler, |
| 1675 TextElement elm, | 1685 uc16 c, |
| 1676 Vector<const uc16> quarks, | |
| 1677 Label* on_failure, | 1686 Label* on_failure, |
| 1678 int cp_offset, | 1687 int cp_offset, |
| 1679 bool check_offset) { | 1688 bool check, |
| 1689 bool preloaded) { |
| 1680 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 1690 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 1681 // It is vital that this loop is backwards due to the unchecked character | 1691 int length = uncanonicalize.get(c, '\0', chars); |
| 1682 // load below. | 1692 if (length <= 1) return false; |
| 1683 for (int i = quarks.length() - 1; i >= 0; i--) { | 1693 // We may not need to check against the end of the input string |
| 1684 uc16 c = quarks[i]; | 1694 // if this character lies before a character that matched. |
| 1685 int length = uncanonicalize.get(c, '\0', chars); | 1695 if (!preloaded) { |
| 1686 if (length <= 1) continue; | 1696 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check); |
| 1687 if (check_offset && i == quarks.length() - 1) { | 1697 } |
| 1688 macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure); | 1698 Label ok; |
| 1689 } else { | 1699 ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4); |
| 1690 // Here we don't need to check against the end of the input string | 1700 switch (length) { |
| 1691 // since this character lies before a character that matched. | 1701 case 2: { |
| 1692 macro_assembler->LoadCurrentCharacterUnchecked(cp_offset + i); | 1702 if (ShortCutEmitCharacterPair(macro_assembler, |
| 1703 chars[0], |
| 1704 chars[1], |
| 1705 on_failure)) { |
| 1706 } else { |
| 1707 macro_assembler->CheckCharacter(chars[0], &ok); |
| 1708 macro_assembler->CheckNotCharacter(chars[1], on_failure); |
| 1709 macro_assembler->Bind(&ok); |
| 1710 } |
| 1711 break; |
| 1693 } | 1712 } |
| 1694 Label ok; | 1713 case 4: |
| 1695 ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4); | 1714 macro_assembler->CheckCharacter(chars[3], &ok); |
| 1696 switch (length) { | 1715 // Fall through! |
| 1697 case 2: { | 1716 case 3: |
| 1698 if (ShortCutEmitCharacterPair(macro_assembler, | 1717 macro_assembler->CheckCharacter(chars[0], &ok); |
| 1699 chars[0], | 1718 macro_assembler->CheckCharacter(chars[1], &ok); |
| 1700 chars[1], | 1719 macro_assembler->CheckNotCharacter(chars[2], on_failure); |
| 1701 on_failure)) { | 1720 macro_assembler->Bind(&ok); |
| 1702 } else { | 1721 break; |
| 1703 macro_assembler->CheckCharacter(chars[0], &ok); | 1722 default: |
| 1704 macro_assembler->CheckNotCharacter(chars[1], on_failure); | 1723 UNREACHABLE(); |
| 1705 macro_assembler->Bind(&ok); | 1724 break; |
| 1706 } | |
| 1707 break; | |
| 1708 } | |
| 1709 case 4: | |
| 1710 macro_assembler->CheckCharacter(chars[3], &ok); | |
| 1711 // Fall through! | |
| 1712 case 3: | |
| 1713 macro_assembler->CheckCharacter(chars[0], &ok); | |
| 1714 macro_assembler->CheckCharacter(chars[1], &ok); | |
| 1715 macro_assembler->CheckNotCharacter(chars[2], on_failure); | |
| 1716 macro_assembler->Bind(&ok); | |
| 1717 break; | |
| 1718 default: | |
| 1719 UNREACHABLE(); | |
| 1720 break; | |
| 1721 } | |
| 1722 } | 1725 } |
| 1726 return true; |
| 1723 } | 1727 } |
| 1724 | 1728 |
| 1725 | 1729 |
| 1726 static void EmitCharClass(RegExpMacroAssembler* macro_assembler, | 1730 static void EmitCharClass(RegExpMacroAssembler* macro_assembler, |
| 1727 RegExpCharacterClass* cc, | 1731 RegExpCharacterClass* cc, |
| 1728 int cp_offset, | 1732 int cp_offset, |
| 1729 Label* on_failure, | 1733 Label* on_failure, |
| 1730 bool check_offset, | 1734 bool check_offset, |
| 1731 bool ascii) { | 1735 bool ascii, |
| 1736 bool preloaded) { |
| 1732 ZoneList<CharacterRange>* ranges = cc->ranges(); | 1737 ZoneList<CharacterRange>* ranges = cc->ranges(); |
| 1733 int max_char; | 1738 int max_char; |
| 1734 if (ascii) { | 1739 if (ascii) { |
| 1735 max_char = String::kMaxAsciiCharCode; | 1740 max_char = String::kMaxAsciiCharCode; |
| 1736 } else { | 1741 } else { |
| 1737 max_char = String::kMaxUC16CharCode; | 1742 max_char = String::kMaxUC16CharCode; |
| 1738 } | 1743 } |
| 1739 | 1744 |
| 1740 Label success; | 1745 Label success; |
| 1741 | 1746 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1767 ranges->at(0).IsEverything(max_char)) { | 1772 ranges->at(0).IsEverything(max_char)) { |
| 1768 // This is a common case hit by non-anchored expressions. | 1773 // This is a common case hit by non-anchored expressions. |
| 1769 // TODO(erikcorry): We should have a macro assembler instruction that just | 1774 // TODO(erikcorry): We should have a macro assembler instruction that just |
| 1770 // checks for end of string without loading the character. | 1775 // checks for end of string without loading the character. |
| 1771 if (check_offset) { | 1776 if (check_offset) { |
| 1772 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure); | 1777 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure); |
| 1773 } | 1778 } |
| 1774 return; | 1779 return; |
| 1775 } | 1780 } |
| 1776 | 1781 |
| 1777 if (check_offset) { | 1782 if (!preloaded) { |
| 1778 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure); | 1783 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check_offset); |
| 1779 } else { | |
| 1780 // Here we don't need to check against the end of the input string | |
| 1781 // since this character lies before a character that matched. | |
| 1782 macro_assembler->LoadCurrentCharacterUnchecked(cp_offset); | |
| 1783 } | 1784 } |
| 1784 | 1785 |
| 1785 for (int i = 0; i <= last_valid_range; i++) { | 1786 for (int i = 0; i < last_valid_range; i++) { |
| 1786 CharacterRange& range = ranges->at(i); | 1787 CharacterRange& range = ranges->at(i); |
| 1787 Label next_range; | 1788 Label next_range; |
| 1788 uc16 from = range.from(); | 1789 uc16 from = range.from(); |
| 1789 uc16 to = range.to(); | 1790 uc16 to = range.to(); |
| 1790 if (from > max_char) { | 1791 if (from > max_char) { |
| 1791 continue; | 1792 continue; |
| 1792 } | 1793 } |
| 1793 if (to > max_char) to = max_char; | 1794 if (to > max_char) to = max_char; |
| 1794 if (to == from) { | 1795 if (to == from) { |
| 1795 macro_assembler->CheckCharacter(to, char_is_in_class); | 1796 macro_assembler->CheckCharacter(to, char_is_in_class); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1836 } else { | 1837 } else { |
| 1837 if (cc->is_negated()) { | 1838 if (cc->is_negated()) { |
| 1838 macro_assembler->GoTo(on_failure); | 1839 macro_assembler->GoTo(on_failure); |
| 1839 } | 1840 } |
| 1840 } | 1841 } |
| 1841 } | 1842 } |
| 1842 macro_assembler->Bind(&success); | 1843 macro_assembler->Bind(&success); |
| 1843 } | 1844 } |
| 1844 | 1845 |
| 1845 | 1846 |
| 1847 RegExpNode::~RegExpNode() { |
| 1848 } |
| 1849 |
| 1850 |
| 1846 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, | 1851 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, |
| 1847 GenerationVariant* variant) { | 1852 GenerationVariant* variant) { |
| 1848 // TODO(erikcorry): Implement support. | 1853 // TODO(erikcorry): Implement support. |
| 1849 if (info_.follows_word_interest || | 1854 if (info_.follows_word_interest || |
| 1850 info_.follows_newline_interest || | 1855 info_.follows_newline_interest || |
| 1851 info_.follows_start_interest) { | 1856 info_.follows_start_interest) { |
| 1852 return FAIL; | 1857 return FAIL; |
| 1853 } | 1858 } |
| 1854 | 1859 |
| 1855 // If we are generating a greedy loop then don't stop and don't reuse code. | 1860 // If we are generating a greedy loop then don't stop and don't reuse code. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1886 } | 1891 } |
| 1887 | 1892 |
| 1888 // If we get here there have been too many variants generated or recursion | 1893 // If we get here there have been too many variants generated or recursion |
| 1889 // is too deep. Time to switch to a generic version. The code for | 1894 // is too deep. Time to switch to a generic version. The code for |
| 1890 // generic versions above can handle deep recursion properly. | 1895 // generic versions above can handle deep recursion properly. |
| 1891 bool ok = variant->Flush(compiler, this); | 1896 bool ok = variant->Flush(compiler, this); |
| 1892 return ok ? DONE : FAIL; | 1897 return ok ? DONE : FAIL; |
| 1893 } | 1898 } |
| 1894 | 1899 |
| 1895 | 1900 |
| 1901 int ActionNode::EatsAtLeast(int recursion_depth) { |
| 1902 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; |
| 1903 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! |
| 1904 return on_success()->EatsAtLeast(recursion_depth + 1); |
| 1905 } |
| 1906 |
| 1907 |
| 1908 int TextNode::EatsAtLeast(int recursion_depth) { |
| 1909 int answer = Length(); |
| 1910 if (answer >= 4) return answer; |
| 1911 if (recursion_depth > RegExpCompiler::kMaxRecursion) return answer; |
| 1912 return answer + on_success()->EatsAtLeast(recursion_depth + 1); |
| 1913 } |
| 1914 |
| 1915 |
| 1916 int ChoiceNode::EatsAtLeastHelper(int recursion_depth, |
| 1917 RegExpNode* ignore_this_node) { |
| 1918 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; |
| 1919 int min = 100; |
| 1920 int choice_count = alternatives_->length(); |
| 1921 for (int i = 0; i < choice_count; i++) { |
| 1922 RegExpNode* node = alternatives_->at(i).node(); |
| 1923 if (node == ignore_this_node) continue; |
| 1924 int node_eats_at_least = node->EatsAtLeast(recursion_depth + 1); |
| 1925 if (node_eats_at_least < min) min = node_eats_at_least; |
| 1926 } |
| 1927 return min; |
| 1928 } |
| 1929 |
| 1930 |
| 1931 int LoopChoiceNode::EatsAtLeast(int recursion_depth) { |
| 1932 return EatsAtLeastHelper(recursion_depth, loop_node_); |
| 1933 } |
| 1934 |
| 1935 |
| 1936 int ChoiceNode::EatsAtLeast(int recursion_depth) { |
| 1937 return EatsAtLeastHelper(recursion_depth, NULL); |
| 1938 } |
| 1939 |
| 1940 |
| 1941 // Takes the left-most 1-bit and smears it out, setting all bits to its right. |
| 1942 static inline uint32_t SmearBitsRight(uint32_t v) { |
| 1943 v |= v >> 1; |
| 1944 v |= v >> 2; |
| 1945 v |= v >> 4; |
| 1946 v |= v >> 8; |
| 1947 v |= v >> 16; |
| 1948 return v; |
| 1949 } |
| 1950 |
| 1951 |
| 1952 bool QuickCheckDetails::Rationalize(bool asc) { |
| 1953 bool found_useful_op = false; |
| 1954 uint32_t char_mask; |
| 1955 if (asc) { |
| 1956 char_mask = String::kMaxAsciiCharCode; |
| 1957 } else { |
| 1958 char_mask = String::kMaxUC16CharCode; |
| 1959 } |
| 1960 mask_ = 0; |
| 1961 value_ = 0; |
| 1962 int char_shift = 0; |
| 1963 for (int i = 0; i < characters_; i++) { |
| 1964 Position* pos = &positions_[i]; |
| 1965 if ((pos->mask & String::kMaxAsciiCharCode) != 0) { |
| 1966 found_useful_op = true; |
| 1967 } |
| 1968 mask_ |= (pos->mask & char_mask) << char_shift; |
| 1969 value_ |= (pos->value & char_mask) << char_shift; |
| 1970 char_shift += asc ? 8 : 16; |
| 1971 } |
| 1972 return found_useful_op; |
| 1973 } |
| 1974 |
| 1975 |
| 1976 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, |
| 1977 GenerationVariant* variant, |
| 1978 bool preload_has_checked_bounds, |
| 1979 Label* on_possible_success, |
| 1980 QuickCheckDetails* details, |
| 1981 bool fall_through_on_failure) { |
| 1982 if (details->characters() == 0) return false; |
| 1983 GetQuickCheckDetails(details, compiler, 0); |
| 1984 if (!details->Rationalize(compiler->ascii())) return false; |
| 1985 uint32_t mask = details->mask(); |
| 1986 uint32_t value = details->value(); |
| 1987 |
| 1988 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1989 |
| 1990 if (variant->characters_preloaded() != details->characters()) { |
| 1991 assembler->LoadCurrentCharacter(variant->cp_offset(), |
| 1992 variant->backtrack(), |
| 1993 !preload_has_checked_bounds, |
| 1994 details->characters()); |
| 1995 } |
| 1996 |
| 1997 |
| 1998 bool need_mask = true; |
| 1999 |
| 2000 if (details->characters() == 1) { |
| 2001 // If number of characters preloaded is 1 then we used a byte or 16 bit |
| 2002 // load so the value is already masked down. |
| 2003 uint32_t char_mask; |
| 2004 if (compiler->ascii()) { |
| 2005 char_mask = String::kMaxAsciiCharCode; |
| 2006 } else { |
| 2007 char_mask = String::kMaxUC16CharCode; |
| 2008 } |
| 2009 if ((mask & char_mask) == char_mask) need_mask = false; |
| 2010 } else { |
| 2011 // For 2-character preloads in ASCII mode we also use a 16 bit load with |
| 2012 // zero extend. |
| 2013 if (details->characters() == 2 && compiler->ascii()) { |
| 2014 if ((mask & 0xffff) == 0xffff) need_mask = false; |
| 2015 } else { |
| 2016 if (mask == 0xffffffff) need_mask = false; |
| 2017 } |
| 2018 } |
| 2019 |
| 2020 if (fall_through_on_failure) { |
| 2021 if (need_mask) { |
| 2022 assembler->CheckCharacterAfterAnd(value, mask, on_possible_success); |
| 2023 } else { |
| 2024 assembler->CheckCharacter(value, on_possible_success); |
| 2025 } |
| 2026 } else { |
| 2027 if (need_mask) { |
| 2028 assembler->CheckNotCharacterAfterAnd(value, mask, variant->backtrack()); |
| 2029 } else { |
| 2030 assembler->CheckNotCharacter(value, variant->backtrack()); |
| 2031 } |
| 2032 } |
| 2033 return true; |
| 2034 } |
| 2035 |
| 2036 |
| 2037 // Here is the meat of GetQuickCheckDetails (see also the comment on the |
| 2038 // super-class in the .h file). |
| 2039 // |
| 2040 // We iterate along the text object, building up for each character a |
| 2041 // mask and value that can be used to test for a quick failure to match. |
| 2042 // The masks and values for the positions will be combined into a single |
| 2043 // machine word for the current character width in order to be used in |
| 2044 // generating a quick check. |
| 2045 void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2046 RegExpCompiler* compiler, |
| 2047 int characters_filled_in) { |
| 2048 ASSERT(characters_filled_in < details->characters()); |
| 2049 int characters = details->characters(); |
| 2050 int char_mask; |
| 2051 int char_shift; |
| 2052 if (compiler->ascii()) { |
| 2053 char_mask = String::kMaxAsciiCharCode; |
| 2054 char_shift = 8; |
| 2055 } else { |
| 2056 char_mask = String::kMaxUC16CharCode; |
| 2057 char_shift = 16; |
| 2058 } |
| 2059 for (int k = 0; k < elms_->length(); k++) { |
| 2060 TextElement elm = elms_->at(k); |
| 2061 if (elm.type == TextElement::ATOM) { |
| 2062 Vector<const uc16> quarks = elm.data.u_atom->data(); |
| 2063 for (int i = 0; i < characters && i < quarks.length(); i++) { |
| 2064 QuickCheckDetails::Position* pos = |
| 2065 details->positions(characters_filled_in); |
| 2066 if (compiler->ignore_case()) { |
| 2067 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 2068 uc16 c = quarks[i]; |
| 2069 int length = uncanonicalize.get(c, '\0', chars); |
| 2070 if (length < 2) { |
| 2071 // This letter has no case equivalents, so it's nice and simple |
| 2072 // and the mask-compare will determine definitely whether we have |
| 2073 // a match at this character position. |
| 2074 pos->mask = char_mask; |
| 2075 pos->value = c; |
| 2076 pos->determines_perfectly = true; |
| 2077 } else { |
| 2078 uint32_t common_bits = char_mask; |
| 2079 uint32_t bits = chars[0]; |
| 2080 for (int j = 1; j < length; j++) { |
| 2081 uint32_t differing_bits = ((chars[j] & common_bits) ^ bits); |
| 2082 common_bits ^= differing_bits; |
| 2083 bits &= common_bits; |
| 2084 } |
| 2085 // If length is 2 and common bits has only one zero in it then |
| 2086 // our mask and compare instruction will determine definitely |
| 2087 // whether we have a match at this character position. Otherwise |
| 2088 // it can only be an approximate check. |
| 2089 uint32_t one_zero = (common_bits | ~char_mask); |
| 2090 if (length == 2 && ((~one_zero) & ((~one_zero) - 1)) == 0) { |
| 2091 pos->determines_perfectly = true; |
| 2092 } |
| 2093 pos->mask = common_bits; |
| 2094 pos->value = bits; |
| 2095 } |
| 2096 } else { |
| 2097 // Don't ignore case. Nice simple case where the mask-compare will |
| 2098 // determine definitely whether we have a match at this character |
| 2099 // position. |
| 2100 pos->mask = char_mask; |
| 2101 pos->value = quarks[i]; |
| 2102 pos->determines_perfectly = true; |
| 2103 } |
| 2104 characters_filled_in++; |
| 2105 ASSERT(characters_filled_in <= details->characters()); |
| 2106 if (characters_filled_in == details->characters()) { |
| 2107 return; |
| 2108 } |
| 2109 } |
| 2110 } else { |
| 2111 QuickCheckDetails::Position* pos = |
| 2112 details->positions(characters_filled_in); |
| 2113 RegExpCharacterClass* tree = elm.data.u_char_class; |
| 2114 ZoneList<CharacterRange>* ranges = tree->ranges(); |
| 2115 CharacterRange range = ranges->at(0); |
| 2116 if (tree->is_negated()) { |
| 2117 // A quick check uses multi-character mask and compare. There is no |
| 2118 // useful way to incorporate a negative char class into this scheme |
| 2119 // so we just conservatively create a mask and value that will always |
| 2120 // succeed. |
| 2121 pos->mask = 0; |
| 2122 pos->value = 0; |
| 2123 } else { |
| 2124 uint32_t differing_bits = (range.from() ^ range.to()); |
| 2125 // A mask and compare is only perfect if the differing bits form a |
| 2126 // number like 00011111 with one single block of trailing 1s. |
| 2127 if ((differing_bits & (differing_bits + 1)) == 0) { |
| 2128 pos->determines_perfectly = true; |
| 2129 } |
| 2130 uint32_t common_bits = ~SmearBitsRight(differing_bits); |
| 2131 uint32_t bits = (range.from() & common_bits); |
| 2132 for (int i = 1; i < ranges->length(); i++) { |
| 2133 // Here we are combining more ranges into the mask and compare |
| 2134 // value. With each new range the mask becomes more sparse and |
| 2135 // so the chances of a false positive rise. A character class |
| 2136 // with multiple ranges is assumed never to be equivalent to a |
| 2137 // mask and compare operation. |
| 2138 pos->determines_perfectly = false; |
| 2139 CharacterRange range = ranges->at(i); |
| 2140 uint32_t new_common_bits = (range.from() ^ range.to()); |
| 2141 new_common_bits = ~SmearBitsRight(new_common_bits); |
| 2142 common_bits &= new_common_bits; |
| 2143 bits &= new_common_bits; |
| 2144 uint32_t differing_bits = (range.from() & common_bits) ^ bits; |
| 2145 common_bits ^= differing_bits; |
| 2146 bits &= common_bits; |
| 2147 } |
| 2148 pos->mask = common_bits; |
| 2149 pos->value = bits; |
| 2150 } |
| 2151 characters_filled_in++; |
| 2152 ASSERT(characters_filled_in <= details->characters()); |
| 2153 if (characters_filled_in == details->characters()) { |
| 2154 return; |
| 2155 } |
| 2156 } |
| 2157 } |
| 2158 ASSERT(characters_filled_in != details->characters()); |
| 2159 on_success()-> GetQuickCheckDetails(details, compiler, characters_filled_in); |
| 2160 } |
| 2161 |
| 2162 |
| 2163 void QuickCheckDetails::Clear() { |
| 2164 for (int i = 0; i < characters_; i++) { |
| 2165 positions_[i].mask = 0; |
| 2166 positions_[i].value = 0; |
| 2167 positions_[i].determines_perfectly = false; |
| 2168 } |
| 2169 characters_ = 0; |
| 2170 } |
| 2171 |
| 2172 |
| 2173 void QuickCheckDetails::Advance(int by, bool ascii) { |
| 2174 ASSERT(by > 0); |
| 2175 if (by >= characters_) { |
| 2176 Clear(); |
| 2177 return; |
| 2178 } |
| 2179 for (int i = 0; i < characters_ - by; i++) { |
| 2180 positions_[i] = positions_[by + i]; |
| 2181 } |
| 2182 for (int i = characters_ - by; i < characters_; i++) { |
| 2183 positions_[i].mask = 0; |
| 2184 positions_[i].value = 0; |
| 2185 positions_[i].determines_perfectly = false; |
| 2186 } |
| 2187 characters_ -= by; |
| 2188 // We could change mask_ and value_ here but we would never advance unless |
| 2189 // they had already been used in a check and they won't be used again because |
| 2190 // it would gain us nothing. So there's no point. |
| 2191 } |
| 2192 |
| 2193 |
| 2194 void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) { |
| 2195 ASSERT(characters_ == other->characters_); |
| 2196 for (int i = from_index; i < characters_; i++) { |
| 2197 QuickCheckDetails::Position* pos = positions(i); |
| 2198 QuickCheckDetails::Position* other_pos = other->positions(i); |
| 2199 if (pos->mask != other_pos->mask || |
| 2200 pos->value != other_pos->value || |
| 2201 !other_pos->determines_perfectly) { |
| 2202 // Our mask-compare operation will be approximate unless we have the |
| 2203 // exact same operation on both sides of the alternation. |
| 2204 pos->determines_perfectly = false; |
| 2205 } |
| 2206 pos->mask &= other_pos->mask; |
| 2207 pos->value &= pos->mask; |
| 2208 other_pos->value &= pos->mask; |
| 2209 uc16 differing_bits = (pos->value ^ other_pos->value); |
| 2210 pos->mask &= ~differing_bits; |
| 2211 pos->value &= pos->mask; |
| 2212 } |
| 2213 } |
| 2214 |
| 2215 |
| 2216 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2217 RegExpCompiler* compiler, |
| 2218 int characters_filled_in) { |
| 2219 if (body_can_be_zero_length_) return; |
| 2220 return ChoiceNode::GetQuickCheckDetails(details, |
| 2221 compiler, |
| 2222 characters_filled_in); |
| 2223 } |
| 2224 |
| 2225 |
| 2226 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2227 RegExpCompiler* compiler, |
| 2228 int characters_filled_in) { |
| 2229 int choice_count = alternatives_->length(); |
| 2230 ASSERT(choice_count > 0); |
| 2231 alternatives_->at(0).node()->GetQuickCheckDetails(details, |
| 2232 compiler, |
| 2233 characters_filled_in); |
| 2234 for (int i = 1; i < choice_count; i++) { |
| 2235 QuickCheckDetails new_details(details->characters()); |
| 2236 RegExpNode* node = alternatives_->at(i).node(); |
| 2237 node->GetQuickCheckDetails(&new_details, compiler, characters_filled_in); |
| 2238 // Here we merge the quick match details of the two branches. |
| 2239 details->Merge(&new_details, characters_filled_in); |
| 2240 } |
| 2241 } |
| 2242 |
| 2243 |
| 2244 // We call this repeatedly to generate code for each pass over the text node. |
| 2245 // The passes are in increasing order of difficulty because we hope one |
| 2246 // of the first passes will fail in which case we are saved the work of the |
| 2247 // later passes. for example for the case independent regexp /%[asdfghjkl]a/ |
| 2248 // we will check the '%' in the first pass, the case independent 'a' in the |
| 2249 // second pass and the character class in the last pass. |
| 2250 // |
| 2251 // The passes are done from right to left, so for example to test for /bar/ |
| 2252 // we will first test for an 'r' with offset 2, then an 'a' with offset 1 |
| 2253 // and then a 'b' with offset 0. This means we can avoid the end-of-input |
| 2254 // bounds check most of the time. In the example we only need to check for |
| 2255 // end-of-input when loading the putative 'r'. |
| 2256 // |
| 2257 // A slight complication involves the fact that the first character may already |
| 2258 // be fetched into a register by the previous node. In this case we want to |
| 2259 // do the test for that character first. We do this in separate passes. The |
| 2260 // 'preloaded' argument indicates that we are doing such a 'pass'. If such a |
| 2261 // pass has been performed then subsequent passes will have true in |
| 2262 // first_element_checked to indicate that that character does not need to be |
| 2263 // checked again. |
| 2264 // |
| 2265 // In addition to all this we are passed a GenerationVariant, which can |
| 2266 // contain an AlternativeGeneration object. In this AlternativeGeneration |
| 2267 // object we can see details of any quick check that was already passed in |
| 2268 // order to get to the code we are now generating. The quick check can involve |
| 2269 // loading characters, which means we do not need to recheck the bounds |
| 2270 // up to the limit the quick check already checked. In addition the quick |
| 2271 // check can have involved a mask and compare operation which may simplify |
| 2272 // or obviate the need for further checks at some character positions. |
| 2273 void TextNode::TextEmitPass(RegExpCompiler* compiler, |
| 2274 TextEmitPassType pass, |
| 2275 bool preloaded, |
| 2276 GenerationVariant* variant, |
| 2277 bool first_element_checked, |
| 2278 int* checked_up_to) { |
| 2279 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2280 bool ascii = compiler->ascii(); |
| 2281 Label* backtrack = variant->backtrack(); |
| 2282 QuickCheckDetails* quick_check = variant->quick_check_performed(); |
| 2283 int element_count = elms_->length(); |
| 2284 for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) { |
| 2285 TextElement elm = elms_->at(i); |
| 2286 int cp_offset = variant->cp_offset() + elm.cp_offset; |
| 2287 if (elm.type == TextElement::ATOM) { |
| 2288 if (pass == NON_ASCII_MATCH || |
| 2289 pass == CHARACTER_MATCH || |
| 2290 pass == CASE_CHARACTER_MATCH) { |
| 2291 Vector<const uc16> quarks = elm.data.u_atom->data(); |
| 2292 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { |
| 2293 bool bound_checked = true; // Most ops will check their bounds. |
| 2294 if (first_element_checked && i == 0 && j == 0) continue; |
| 2295 if (quick_check != NULL && |
| 2296 elm.cp_offset + j < quick_check->characters() && |
| 2297 quick_check->positions(elm.cp_offset + j)->determines_perfectly) { |
| 2298 continue; |
| 2299 } |
| 2300 if (pass == NON_ASCII_MATCH) { |
| 2301 ASSERT(ascii); |
| 2302 if (quarks[j] > String::kMaxAsciiCharCode) { |
| 2303 assembler->GoTo(backtrack); |
| 2304 return; |
| 2305 } |
| 2306 } else if (pass == CHARACTER_MATCH) { |
| 2307 if (compiler->ignore_case()) { |
| 2308 bound_checked = EmitAtomNonLetter(assembler, |
| 2309 quarks[j], |
| 2310 backtrack, |
| 2311 cp_offset + j, |
| 2312 *checked_up_to < cp_offset + j, |
| 2313 preloaded); |
| 2314 } else { |
| 2315 if (!preloaded) { |
| 2316 assembler->LoadCurrentCharacter(cp_offset + j, |
| 2317 backtrack, |
| 2318 *checked_up_to < cp_offset + j); |
| 2319 } |
| 2320 assembler->CheckNotCharacter(quarks[j], backtrack); |
| 2321 } |
| 2322 } else { |
| 2323 ASSERT_EQ(pass, CASE_CHARACTER_MATCH); |
| 2324 ASSERT(compiler->ignore_case()); |
| 2325 bound_checked = EmitAtomLetter(assembler, |
| 2326 quarks[j], |
| 2327 backtrack, |
| 2328 cp_offset + j, |
| 2329 *checked_up_to < cp_offset + j, |
| 2330 preloaded); |
| 2331 } |
| 2332 if (pass != NON_ASCII_MATCH && bound_checked) { |
| 2333 if (cp_offset + j > *checked_up_to) { |
| 2334 *checked_up_to = cp_offset + j; |
| 2335 } |
| 2336 } |
| 2337 } |
| 2338 } |
| 2339 } else { |
| 2340 ASSERT_EQ(elm.type, TextElement::CHAR_CLASS); |
| 2341 if (first_element_checked && i == 0) continue; |
| 2342 if (quick_check != NULL && |
| 2343 elm.cp_offset < quick_check->characters() && |
| 2344 quick_check->positions(elm.cp_offset)->determines_perfectly) { |
| 2345 continue; |
| 2346 } |
| 2347 if (pass == CHARACTER_CLASS_MATCH) { |
| 2348 RegExpCharacterClass* cc = elm.data.u_char_class; |
| 2349 EmitCharClass(assembler, |
| 2350 cc, |
| 2351 cp_offset, |
| 2352 backtrack, |
| 2353 *checked_up_to < cp_offset, |
| 2354 ascii, |
| 2355 preloaded); |
| 2356 if (cp_offset > *checked_up_to) { |
| 2357 *checked_up_to = cp_offset; |
| 2358 } |
| 2359 } |
| 2360 } |
| 2361 } |
| 2362 } |
| 2363 |
| 2364 |
| 2365 int TextNode::Length() { |
| 2366 TextElement elm = elms_->last(); |
| 2367 ASSERT(elm.cp_offset >= 0); |
| 2368 if (elm.type == TextElement::ATOM) { |
| 2369 return elm.cp_offset + elm.data.u_atom->data().length(); |
| 2370 } else { |
| 2371 return elm.cp_offset + 1; |
| 2372 } |
| 2373 } |
| 2374 |
| 2375 |
| 1896 // This generates the code to match a text node. A text node can contain | 2376 // This generates the code to match a text node. A text node can contain |
| 1897 // straight character sequences (possibly to be matched in a case-independent | 2377 // straight character sequences (possibly to be matched in a case-independent |
| 1898 // way) and character classes. In order to be most efficient we test for the | 2378 // way) and character classes. For efficiency we do not do this in a single |
| 1899 // simple things first and then move on to the more complicated things. The | 2379 // pass from left to right. Instead we pass over the text node several times, |
| 1900 // simplest thing is a non-letter or a letter if we are matching case. The | 2380 // emitting code for some character positions every time. See the comment on |
| 1901 // next-most simple thing is a case-independent letter. The least simple is | 2381 // TextEmitPass for details. |
| 1902 // a character class. Another optimization is that we test the last one first. | |
| 1903 // If that succeeds we don't need to test for the end of the string when we | |
| 1904 // load other characters. | |
| 1905 bool TextNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2382 bool TextNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { |
| 1906 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | |
| 1907 Label *backtrack = variant->backtrack(); | |
| 1908 LimitResult limit_result = LimitVersions(compiler, variant); | 2383 LimitResult limit_result = LimitVersions(compiler, variant); |
| 1909 if (limit_result == FAIL) return false; | 2384 if (limit_result == FAIL) return false; |
| 1910 if (limit_result == DONE) return true; | 2385 if (limit_result == DONE) return true; |
| 1911 ASSERT(limit_result == CONTINUE); | 2386 ASSERT(limit_result == CONTINUE); |
| 1912 | 2387 |
| 1913 int element_count = elms_->length(); | 2388 if (info()->follows_word_interest || |
| 1914 ASSERT(element_count != 0); | 2389 info()->follows_newline_interest || |
| 2390 info()->follows_start_interest) { |
| 2391 return false; |
| 2392 } |
| 2393 |
| 1915 if (info()->at_end) { | 2394 if (info()->at_end) { |
| 1916 macro_assembler->GoTo(backtrack); | 2395 compiler->macro_assembler()->GoTo(variant->backtrack()); |
| 1917 return true; | 2396 return true; |
| 1918 } | 2397 } |
| 1919 // First check for non-ASCII text. | 2398 |
| 1920 // TODO(plesner): We should do this at node level. | |
| 1921 if (compiler->ascii()) { | 2399 if (compiler->ascii()) { |
| 1922 for (int i = element_count - 1; i >= 0; i--) { | 2400 int dummy = 0; |
| 1923 TextElement elm = elms_->at(i); | 2401 TextEmitPass(compiler, NON_ASCII_MATCH, false, variant, false, &dummy); |
| 1924 if (elm.type == TextElement::ATOM) { | 2402 } |
| 1925 Vector<const uc16> quarks = elm.data.u_atom->data(); | 2403 |
| 1926 for (int j = quarks.length() - 1; j >= 0; j--) { | 2404 bool first_elt_done = false; |
| 1927 if (quarks[j] > String::kMaxAsciiCharCode) { | 2405 int bound_checked_to = variant->cp_offset() - 1; |
| 1928 macro_assembler->GoTo(backtrack); | 2406 QuickCheckDetails* quick_check = variant->quick_check_performed(); |
| 1929 return true; | 2407 bound_checked_to += Max(quick_check->characters(), |
| 1930 } | 2408 variant->characters_preloaded()); |
| 1931 } | 2409 |
| 1932 } else { | 2410 // If a character is preloaded into the current character register then |
| 1933 ASSERT_EQ(elm.type, TextElement::CHAR_CLASS); | 2411 // check that now. |
| 1934 } | 2412 if (variant->characters_preloaded() == 1) { |
| 1935 } | 2413 TextEmitPass(compiler, |
| 1936 } | 2414 CHARACTER_MATCH, |
| 1937 // Second, handle straight character matches. | 2415 true, |
| 1938 int checked_up_to = -1; | 2416 variant, |
| 1939 for (int i = element_count - 1; i >= 0; i--) { | 2417 false, |
| 1940 TextElement elm = elms_->at(i); | 2418 &bound_checked_to); |
| 1941 ASSERT(elm.cp_offset >= 0); | 2419 if (compiler->ignore_case()) { |
| 1942 int cp_offset = variant->cp_offset() + elm.cp_offset; | 2420 TextEmitPass(compiler, |
| 1943 if (elm.type == TextElement::ATOM) { | 2421 CASE_CHARACTER_MATCH, |
| 1944 Vector<const uc16> quarks = elm.data.u_atom->data(); | 2422 true, |
| 1945 int last_cp_offset = cp_offset + quarks.length(); | 2423 variant, |
| 1946 if (compiler->ignore_case()) { | 2424 false, |
| 1947 EmitAtomNonLetters(macro_assembler, | 2425 &bound_checked_to); |
| 1948 elm, | 2426 } |
| 1949 quarks, | 2427 TextEmitPass(compiler, |
| 1950 backtrack, | 2428 CHARACTER_CLASS_MATCH, |
| 1951 cp_offset, | 2429 true, |
| 1952 checked_up_to < last_cp_offset); | 2430 variant, |
| 1953 } else { | 2431 false, |
| 1954 macro_assembler->CheckCharacters(quarks, | 2432 &bound_checked_to); |
| 1955 cp_offset, | 2433 first_elt_done = true; |
| 1956 backtrack, | 2434 } |
| 1957 checked_up_to < last_cp_offset); | 2435 |
| 1958 } | 2436 TextEmitPass(compiler, |
| 1959 if (last_cp_offset > checked_up_to) checked_up_to = last_cp_offset - 1; | 2437 CHARACTER_MATCH, |
| 1960 } else { | 2438 false, |
| 1961 ASSERT_EQ(elm.type, TextElement::CHAR_CLASS); | 2439 variant, |
| 1962 } | 2440 first_elt_done, |
| 1963 } | 2441 &bound_checked_to); |
| 1964 // Third, handle case independent letter matches if any. | |
| 1965 if (compiler->ignore_case()) { | 2442 if (compiler->ignore_case()) { |
| 1966 for (int i = element_count - 1; i >= 0; i--) { | 2443 TextEmitPass(compiler, |
| 1967 TextElement elm = elms_->at(i); | 2444 CASE_CHARACTER_MATCH, |
| 1968 int cp_offset = variant->cp_offset() + elm.cp_offset; | 2445 false, |
| 1969 if (elm.type == TextElement::ATOM) { | 2446 variant, |
| 1970 Vector<const uc16> quarks = elm.data.u_atom->data(); | 2447 first_elt_done, |
| 1971 int last_cp_offset = cp_offset + quarks.length(); | 2448 &bound_checked_to); |
| 1972 EmitAtomLetters(macro_assembler, | 2449 } |
| 1973 elm, | 2450 TextEmitPass(compiler, |
| 1974 quarks, | 2451 CHARACTER_CLASS_MATCH, |
| 1975 backtrack, | 2452 false, |
| 1976 cp_offset, | 2453 variant, |
| 1977 checked_up_to < last_cp_offset); | 2454 first_elt_done, |
| 1978 if (last_cp_offset > checked_up_to) checked_up_to = last_cp_offset - 1; | 2455 &bound_checked_to); |
| 1979 } | 2456 |
| 1980 } | 2457 GenerationVariant successor_variant(*variant); |
| 1981 } | 2458 successor_variant.AdvanceVariant(Length(), compiler->ascii()); |
| 1982 // If the fast character matches passed then do the character classes. | |
| 1983 for (int i = element_count - 1; i >= 0; i--) { | |
| 1984 TextElement elm = elms_->at(i); | |
| 1985 int cp_offset = variant->cp_offset() + elm.cp_offset; | |
| 1986 if (elm.type == TextElement::CHAR_CLASS) { | |
| 1987 RegExpCharacterClass* cc = elm.data.u_char_class; | |
| 1988 EmitCharClass(macro_assembler, | |
| 1989 cc, | |
| 1990 cp_offset, | |
| 1991 backtrack, | |
| 1992 checked_up_to < cp_offset, | |
| 1993 compiler->ascii()); | |
| 1994 if (cp_offset > checked_up_to) checked_up_to = cp_offset; | |
| 1995 } | |
| 1996 } | |
| 1997 | |
| 1998 GenerationVariant new_variant(*variant); | |
| 1999 new_variant.set_cp_offset(checked_up_to + 1); | |
| 2000 RecursionCheck rc(compiler); | 2459 RecursionCheck rc(compiler); |
| 2001 return on_success()->Emit(compiler, &new_variant); | 2460 return on_success()->Emit(compiler, &successor_variant); |
| 2461 } |
| 2462 |
| 2463 |
| 2464 void GenerationVariant::AdvanceVariant(int by, bool ascii) { |
| 2465 ASSERT(by > 0); |
| 2466 // We don't have an instruction for shifting the current character register |
| 2467 // down or for using a shifted value for anything so lets just forget that |
| 2468 // we preloaded any characters into it. |
| 2469 characters_preloaded_ = 0; |
| 2470 // Adjust the offsets of the quick check performed information. This |
| 2471 // information is used to find out what we already determined about the |
| 2472 // characters by means of mask and compare. |
| 2473 quick_check_performed_.Advance(by, ascii); |
| 2474 cp_offset_ += by; |
| 2002 } | 2475 } |
| 2003 | 2476 |
| 2004 | 2477 |
| 2005 void TextNode::MakeCaseIndependent() { | 2478 void TextNode::MakeCaseIndependent() { |
| 2006 int element_count = elms_->length(); | 2479 int element_count = elms_->length(); |
| 2007 for (int i = 0; i < element_count; i++) { | 2480 for (int i = 0; i < element_count; i++) { |
| 2008 TextElement elm = elms_->at(i); | 2481 TextElement elm = elms_->at(i); |
| 2009 if (elm.type == TextElement::CHAR_CLASS) { | 2482 if (elm.type == TextElement::CHAR_CLASS) { |
| 2010 RegExpCharacterClass* cc = elm.data.u_char_class; | 2483 RegExpCharacterClass* cc = elm.data.u_char_class; |
| 2011 ZoneList<CharacterRange>* ranges = cc->ranges(); | 2484 ZoneList<CharacterRange>* ranges = cc->ranges(); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2053 return kNodeIsTooComplexForGreedyLoops; | 2526 return kNodeIsTooComplexForGreedyLoops; |
| 2054 } | 2527 } |
| 2055 length += node_length; | 2528 length += node_length; |
| 2056 SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node); | 2529 SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node); |
| 2057 node = seq_node->on_success(); | 2530 node = seq_node->on_success(); |
| 2058 } | 2531 } |
| 2059 return length; | 2532 return length; |
| 2060 } | 2533 } |
| 2061 | 2534 |
| 2062 | 2535 |
| 2536 void LoopChoiceNode::AddLoopAlternative(GuardedAlternative alt) { |
| 2537 ASSERT_EQ(loop_node_, NULL); |
| 2538 AddAlternative(alt); |
| 2539 loop_node_ = alt.node(); |
| 2540 } |
| 2541 |
| 2542 |
| 2543 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { |
| 2544 ASSERT_EQ(continue_node_, NULL); |
| 2545 AddAlternative(alt); |
| 2546 continue_node_ = alt.node(); |
| 2547 } |
| 2548 |
| 2549 |
| 2063 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, | 2550 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, |
| 2064 GenerationVariant* variant) { | 2551 GenerationVariant* variant) { |
| 2065 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2552 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2066 if (variant->stop_node() == this) { | 2553 if (variant->stop_node() == this) { |
| 2067 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2554 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2068 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); | 2555 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); |
| 2069 // Update the counter-based backtracking info on the stack. This is an | 2556 // Update the counter-based backtracking info on the stack. This is an |
| 2070 // optimization for greedy loops (see below). | 2557 // optimization for greedy loops (see below). |
| 2071 ASSERT(variant->cp_offset() == text_length); | 2558 ASSERT(variant->cp_offset() == text_length); |
| 2072 macro_assembler->AdvanceCurrentPosition(text_length); | 2559 macro_assembler->AdvanceCurrentPosition(text_length); |
| 2073 macro_assembler->GoTo(variant->loop_label()); | 2560 macro_assembler->GoTo(variant->loop_label()); |
| 2074 return true; | 2561 return true; |
| 2075 } | 2562 } |
| 2076 ASSERT(variant->stop_node() == NULL); | 2563 ASSERT(variant->stop_node() == NULL); |
| 2077 if (!variant->is_trivial()) { | 2564 if (!variant->is_trivial()) { |
| 2078 return variant->Flush(compiler, this); | 2565 return variant->Flush(compiler, this); |
| 2079 } | 2566 } |
| 2080 return ChoiceNode::Emit(compiler, variant); | 2567 return ChoiceNode::Emit(compiler, variant); |
| 2081 } | 2568 } |
| 2082 | 2569 |
| 2083 | 2570 |
| 2571 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { |
| 2572 int preload_characters = EatsAtLeast(0); |
| 2573 #ifdef CAN_READ_UNALIGNED |
| 2574 bool ascii = compiler->ascii(); |
| 2575 if (ascii) { |
| 2576 if (preload_characters > 4) preload_characters = 4; |
| 2577 // We can't preload 3 characters because there is no machine instruction |
| 2578 // to do that. We can't just load 4 because we could be reading |
| 2579 // beyond the end of the string, which could cause a memory fault. |
| 2580 if (preload_characters == 3) preload_characters = 2; |
| 2581 } else { |
| 2582 if (preload_characters > 2) preload_characters = 2; |
| 2583 } |
| 2584 #else |
| 2585 if (preload_characters > 1) preload_characters = 1; |
| 2586 #endif |
| 2587 return preload_characters; |
| 2588 } |
| 2589 |
| 2590 |
| 2591 // This class is used when generating the alternatives in a choice node. It |
| 2592 // records the way the alternative is being code generated. |
| 2593 class AlternativeGeneration: public Malloced { |
| 2594 public: |
| 2595 AlternativeGeneration() |
| 2596 : possible_success(), |
| 2597 expects_preload(false), |
| 2598 after(), |
| 2599 quick_check_details() { } |
| 2600 Label possible_success; |
| 2601 bool expects_preload; |
| 2602 Label after; |
| 2603 QuickCheckDetails quick_check_details; |
| 2604 }; |
| 2605 |
| 2606 |
| 2607 // Creates a list of AlternativeGenerations. If the list has a reasonable |
| 2608 // size then it is on the stack, otherwise the excess is on the heap. |
| 2609 class AlternativeGenerationList { |
| 2610 public: |
| 2611 explicit AlternativeGenerationList(int count) |
| 2612 : alt_gens_(count) { |
| 2613 for (int i = 0; i < count && i < kAFew; i++) { |
| 2614 alt_gens_.Add(a_few_alt_gens_ + i); |
| 2615 } |
| 2616 for (int i = kAFew; i < count; i++) { |
| 2617 alt_gens_.Add(new AlternativeGeneration()); |
| 2618 } |
| 2619 } |
| 2620 ~AlternativeGenerationList() { |
| 2621 for (int i = 0; i < alt_gens_.length(); i++) { |
| 2622 alt_gens_[i]->possible_success.Unuse(); |
| 2623 alt_gens_[i]->after.Unuse(); |
| 2624 } |
| 2625 for (int i = kAFew; i < alt_gens_.length(); i++) { |
| 2626 delete alt_gens_[i]; |
| 2627 alt_gens_[i] = NULL; |
| 2628 } |
| 2629 } |
| 2630 |
| 2631 AlternativeGeneration* at(int i) { |
| 2632 return alt_gens_[i]; |
| 2633 } |
| 2634 private: |
| 2635 static const int kAFew = 10; |
| 2636 ZoneList<AlternativeGeneration*> alt_gens_; |
| 2637 AlternativeGeneration a_few_alt_gens_[kAFew]; |
| 2638 }; |
| 2639 |
| 2640 |
| 2641 /* Code generation for choice nodes. |
| 2642 * |
| 2643 * We generate quick checks that do a mask and compare to eliminate a |
| 2644 * choice. If the quick check succeeds then it jumps to the continuation to |
| 2645 * do slow checks and check subsequent nodes. If it fails (the common case) |
| 2646 * it falls through to the next choice. |
| 2647 * |
| 2648 * Here is the desired flow graph. Nodes directly below each other imply |
| 2649 * fallthrough. Alternatives 1 and 2 have quick checks. Alternative |
| 2650 * 3 doesn't have a quick check so we have to call the slow check. |
| 2651 * Nodes are marked Qn for quick checks and Sn for slow checks. The entire |
| 2652 * regexp continuation is generated directly after the Sn node, up to the |
| 2653 * next GoTo if we decide to reuse some already generated code. Some |
| 2654 * nodes expect preload_characters to be preloaded into the current |
| 2655 * character register. R nodes do this preloading. Vertices are marked |
| 2656 * F for failures and S for success (possible success in the case of quick |
| 2657 * nodes). L, V, < and > are used as arrow heads. |
| 2658 * |
| 2659 * ----------> R |
| 2660 * | |
| 2661 * V |
| 2662 * Q1 -----> S1 |
| 2663 * | S / |
| 2664 * F| / |
| 2665 * | F/ |
| 2666 * | / |
| 2667 * | R |
| 2668 * | / |
| 2669 * V L |
| 2670 * Q2 -----> S2 |
| 2671 * | S / |
| 2672 * F| / |
| 2673 * | F/ |
| 2674 * | / |
| 2675 * | R |
| 2676 * | / |
| 2677 * V L |
| 2678 * S3 |
| 2679 * | |
| 2680 * F| |
| 2681 * | |
| 2682 * R |
| 2683 * | |
| 2684 * backtrack V |
| 2685 * <----------Q4 |
| 2686 * \ F | |
| 2687 * \ |S |
| 2688 * \ F V |
| 2689 * \-----S4 |
| 2690 * |
| 2691 * For greedy loops we reverse our expectation and expect to match rather |
| 2692 * than fail. Therefore we want the loop code to look like this (U is the |
| 2693 * unwind code that steps back in the greedy loop). The following alternatives |
| 2694 * look the same as above. |
| 2695 * _____ |
| 2696 * / \ |
| 2697 * V | |
| 2698 * ----------> S1 | |
| 2699 * /| | |
| 2700 * / |S | |
| 2701 * F/ \_____/ |
| 2702 * / |
| 2703 * |<----------- |
| 2704 * | \ |
| 2705 * V \ |
| 2706 * Q2 ---> S2 \ |
| 2707 * | S / | |
| 2708 * F| / | |
| 2709 * | F/ | |
| 2710 * | / | |
| 2711 * | R | |
| 2712 * | / | |
| 2713 * F VL | |
| 2714 * <------U | |
| 2715 * back |S | |
| 2716 * \______________/ |
| 2717 */ |
| 2718 |
| 2719 |
| 2084 bool ChoiceNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2720 bool ChoiceNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { |
| 2085 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2721 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2086 int choice_count = alternatives_->length(); | 2722 int choice_count = alternatives_->length(); |
| 2087 #ifdef DEBUG | 2723 #ifdef DEBUG |
| 2088 for (int i = 0; i < choice_count - 1; i++) { | 2724 for (int i = 0; i < choice_count - 1; i++) { |
| 2089 GuardedAlternative alternative = alternatives_->at(i); | 2725 GuardedAlternative alternative = alternatives_->at(i); |
| 2090 ZoneList<Guard*>* guards = alternative.guards(); | 2726 ZoneList<Guard*>* guards = alternative.guards(); |
| 2091 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2727 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2092 for (int j = 0; j < guard_count; j++) { | 2728 for (int j = 0; j < guard_count; j++) { |
| 2093 ASSERT(!variant->mentions_reg(guards->at(j)->reg())); | 2729 ASSERT(!variant->mentions_reg(guards->at(j)->reg())); |
| 2094 } | 2730 } |
| 2095 } | 2731 } |
| 2096 #endif | 2732 #endif |
| 2097 | 2733 |
| 2098 LimitResult limit_result = LimitVersions(compiler, variant); | 2734 LimitResult limit_result = LimitVersions(compiler, variant); |
| 2099 if (limit_result == DONE) return true; | 2735 if (limit_result == DONE) return true; |
| 2100 if (limit_result == FAIL) return false; | 2736 if (limit_result == FAIL) return false; |
| 2101 ASSERT(limit_result == CONTINUE); | 2737 ASSERT(limit_result == CONTINUE); |
| 2102 | 2738 |
| 2103 RecursionCheck rc(compiler); | 2739 RecursionCheck rc(compiler); |
| 2104 | 2740 |
| 2105 GenerationVariant* current_variant = variant; | 2741 GenerationVariant* current_variant = variant; |
| 2106 | 2742 |
| 2107 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2743 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2108 bool greedy_loop = false; | 2744 bool greedy_loop = false; |
| 2109 Label greedy_loop_label; | 2745 Label greedy_loop_label; |
| 2110 GenerationVariant counter_backtrack_variant(&greedy_loop_label); | 2746 GenerationVariant counter_backtrack_variant; |
| 2747 counter_backtrack_variant.set_backtrack(&greedy_loop_label); |
| 2111 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { | 2748 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { |
| 2112 // Here we have special handling for greedy loops containing only text nodes | 2749 // Here we have special handling for greedy loops containing only text nodes |
| 2113 // and other simple nodes. These are handled by pushing the current | 2750 // and other simple nodes. These are handled by pushing the current |
| 2114 // position on the stack and then incrementing the current position each | 2751 // position on the stack and then incrementing the current position each |
| 2115 // time around the switch. On backtrack we decrement the current position | 2752 // time around the switch. On backtrack we decrement the current position |
| 2116 // and check it against the pushed value. This avoids pushing backtrack | 2753 // and check it against the pushed value. This avoids pushing backtrack |
| 2117 // information for each iteration of the loop, which could take up a lot of | 2754 // information for each iteration of the loop, which could take up a lot of |
| 2118 // space. | 2755 // space. |
| 2119 greedy_loop = true; | 2756 greedy_loop = true; |
| 2120 ASSERT(variant->stop_node() == NULL); | 2757 ASSERT(variant->stop_node() == NULL); |
| 2121 macro_assembler->PushCurrentPosition(); | 2758 macro_assembler->PushCurrentPosition(); |
| 2122 current_variant = &counter_backtrack_variant; | 2759 current_variant = &counter_backtrack_variant; |
| 2123 Label greedy_match_failed; | 2760 Label greedy_match_failed; |
| 2124 GenerationVariant greedy_match_variant(&greedy_match_failed); | 2761 GenerationVariant greedy_match_variant; |
| 2762 greedy_match_variant.set_backtrack(&greedy_match_failed); |
| 2125 Label loop_label; | 2763 Label loop_label; |
| 2126 macro_assembler->Bind(&loop_label); | 2764 macro_assembler->Bind(&loop_label); |
| 2127 greedy_match_variant.set_stop_node(this); | 2765 greedy_match_variant.set_stop_node(this); |
| 2128 greedy_match_variant.set_loop_label(&loop_label); | 2766 greedy_match_variant.set_loop_label(&loop_label); |
| 2129 bool ok = alternatives_->at(0).node()->Emit(compiler, | 2767 bool ok = alternatives_->at(0).node()->Emit(compiler, |
| 2130 &greedy_match_variant); | 2768 &greedy_match_variant); |
| 2131 macro_assembler->Bind(&greedy_match_failed); | 2769 macro_assembler->Bind(&greedy_match_failed); |
| 2132 if (!ok) { | 2770 if (!ok) { |
| 2133 greedy_loop_label.Unuse(); | 2771 greedy_loop_label.Unuse(); |
| 2134 return false; | 2772 return false; |
| 2135 } | 2773 } |
| 2136 } | 2774 } |
| 2137 | 2775 |
| 2138 Label second_choice; // For use in greedy matches. | 2776 Label second_choice; // For use in greedy matches. |
| 2139 macro_assembler->Bind(&second_choice); | 2777 macro_assembler->Bind(&second_choice); |
| 2140 | 2778 |
| 2779 int first_normal_choice = greedy_loop ? 1 : 0; |
| 2780 |
| 2781 int preload_characters = CalculatePreloadCharacters(compiler); |
| 2782 bool preload_is_current = false; |
| 2783 bool preload_has_checked_bounds = false; |
| 2784 |
| 2785 AlternativeGenerationList alt_gens(choice_count); |
| 2786 |
| 2141 // For now we just call all choices one after the other. The idea ultimately | 2787 // For now we just call all choices one after the other. The idea ultimately |
| 2142 // is to use the Dispatch table to try only the relevant ones. | 2788 // is to use the Dispatch table to try only the relevant ones. |
| 2143 for (int i = greedy_loop ? 1 : 0; i < choice_count - 1; i++) { | 2789 for (int i = first_normal_choice; i < choice_count; i++) { |
| 2144 GuardedAlternative alternative = alternatives_->at(i); | 2790 GuardedAlternative alternative = alternatives_->at(i); |
| 2145 Label after; | 2791 AlternativeGeneration* alt_gen(alt_gens.at(i)); |
| 2792 alt_gen->quick_check_details.set_characters(preload_characters); |
| 2146 ZoneList<Guard*>* guards = alternative.guards(); | 2793 ZoneList<Guard*>* guards = alternative.guards(); |
| 2147 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2794 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2795 |
| 2148 GenerationVariant new_variant(*current_variant); | 2796 GenerationVariant new_variant(*current_variant); |
| 2149 new_variant.set_backtrack(&after); | 2797 new_variant.set_characters_preloaded(preload_is_current ? |
| 2150 for (int j = 0; j < guard_count; j++) { | 2798 preload_characters : |
| 2151 GenerateGuard(macro_assembler, guards->at(j), &new_variant); | 2799 0); |
| 2800 new_variant.quick_check_performed()->Clear(); |
| 2801 alt_gen->expects_preload = preload_is_current; |
| 2802 bool generate_full_check_inline = false; |
| 2803 if (alternative.node()->EmitQuickCheck(compiler, |
| 2804 &new_variant, |
| 2805 preload_has_checked_bounds, |
| 2806 &alt_gen->possible_success, |
| 2807 &alt_gen->quick_check_details, |
| 2808 i < choice_count - 1)) { |
| 2809 // Quick check was generated for this choice. |
| 2810 preload_is_current = true; |
| 2811 preload_has_checked_bounds = true; |
| 2812 // On the last choice in the ChoiceNode we generated the quick |
| 2813 // check to fall through on possible success. So now we need to |
| 2814 // generate the full check inline. |
| 2815 if (i == choice_count - 1) { |
| 2816 macro_assembler->Bind(&alt_gen->possible_success); |
| 2817 new_variant.set_quick_check_performed(&alt_gen->quick_check_details); |
| 2818 new_variant.set_characters_preloaded(preload_characters); |
| 2819 generate_full_check_inline = true; |
| 2820 } |
| 2821 } else { |
| 2822 // No quick check was generated. Put the full code here. |
| 2823 if (i < choice_count - 1) { |
| 2824 new_variant.set_backtrack(&alt_gen->after); |
| 2825 } |
| 2826 generate_full_check_inline = true; |
| 2152 } | 2827 } |
| 2153 if (!alternative.node()->Emit(compiler, &new_variant)) { | 2828 if (generate_full_check_inline) { |
| 2154 after.Unuse(); | 2829 if (preload_is_current) { |
| 2155 return false; | 2830 new_variant.set_characters_preloaded(preload_characters); |
| 2831 } |
| 2832 for (int j = 0; j < guard_count; j++) { |
| 2833 GenerateGuard(macro_assembler, guards->at(j), &new_variant); |
| 2834 } |
| 2835 if (!alternative.node()->Emit(compiler, &new_variant)) { |
| 2836 greedy_loop_label.Unuse(); |
| 2837 return false; |
| 2838 } |
| 2839 preload_is_current = false; |
| 2156 } | 2840 } |
| 2157 macro_assembler->Bind(&after); | 2841 macro_assembler->Bind(&alt_gen->after); |
| 2158 } | 2842 } |
| 2159 GuardedAlternative alternative = alternatives_->at(choice_count - 1); | |
| 2160 ZoneList<Guard*>* guards = alternative.guards(); | |
| 2161 int guard_count = (guards == NULL) ? 0 : guards->length(); | |
| 2162 for (int j = 0; j < guard_count; j++) { | |
| 2163 GenerateGuard(macro_assembler, guards->at(j), current_variant); | |
| 2164 } | |
| 2165 bool ok = alternative.node()->Emit(compiler, current_variant); | |
| 2166 if (!ok) return false; | |
| 2167 if (greedy_loop) { | 2843 if (greedy_loop) { |
| 2168 macro_assembler->Bind(&greedy_loop_label); | 2844 macro_assembler->Bind(&greedy_loop_label); |
| 2169 // If we have unwound to the bottom then backtrack. | 2845 // If we have unwound to the bottom then backtrack. |
| 2170 macro_assembler->CheckGreedyLoop(variant->backtrack()); | 2846 macro_assembler->CheckGreedyLoop(variant->backtrack()); |
| 2171 // Otherwise try the second priority at an earlier position. | 2847 // Otherwise try the second priority at an earlier position. |
| 2172 macro_assembler->AdvanceCurrentPosition(-text_length); | 2848 macro_assembler->AdvanceCurrentPosition(-text_length); |
| 2173 macro_assembler->GoTo(&second_choice); | 2849 macro_assembler->GoTo(&second_choice); |
| 2174 } | 2850 } |
| 2851 // At this point we need to generate slow checks for the alternatives where |
| 2852 // the quick check was inlined. We can recognize these because the associated |
| 2853 // label was bound. |
| 2854 for (int i = first_normal_choice; i < choice_count - 1; i++) { |
| 2855 AlternativeGeneration* alt_gen = alt_gens.at(i); |
| 2856 if (!EmitOutOfLineContinuation(compiler, |
| 2857 current_variant, |
| 2858 alternatives_->at(i), |
| 2859 alt_gen, |
| 2860 preload_characters, |
| 2861 alt_gens.at(i + 1)->expects_preload)) { |
| 2862 return false; |
| 2863 } |
| 2864 } |
| 2175 return true; | 2865 return true; |
| 2176 } | 2866 } |
| 2177 | 2867 |
| 2178 | 2868 |
| 2869 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, |
| 2870 GenerationVariant* variant, |
| 2871 GuardedAlternative alternative, |
| 2872 AlternativeGeneration* alt_gen, |
| 2873 int preload_characters, |
| 2874 bool next_expects_preload) { |
| 2875 if (!alt_gen->possible_success.is_linked()) return true; |
| 2876 |
| 2877 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2878 macro_assembler->Bind(&alt_gen->possible_success); |
| 2879 GenerationVariant out_of_line_variant(*variant); |
| 2880 out_of_line_variant.set_characters_preloaded(preload_characters); |
| 2881 out_of_line_variant.set_quick_check_performed(&alt_gen->quick_check_details); |
| 2882 ZoneList<Guard*>* guards = alternative.guards(); |
| 2883 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2884 if (next_expects_preload) { |
| 2885 Label reload_current_char; |
| 2886 out_of_line_variant.set_backtrack(&reload_current_char); |
| 2887 for (int j = 0; j < guard_count; j++) { |
| 2888 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); |
| 2889 } |
| 2890 bool ok = alternative.node()->Emit(compiler, &out_of_line_variant); |
| 2891 macro_assembler->Bind(&reload_current_char); |
| 2892 // Reload the current character, since the next quick check expects that. |
| 2893 // We don't need to check bounds here because we only get into this |
| 2894 // code through a quick check which already did the checked load. |
| 2895 macro_assembler->LoadCurrentCharacter(variant->cp_offset(), |
| 2896 NULL, |
| 2897 false, |
| 2898 preload_characters); |
| 2899 macro_assembler->GoTo(&(alt_gen->after)); |
| 2900 return ok; |
| 2901 } else { |
| 2902 out_of_line_variant.set_backtrack(&(alt_gen->after)); |
| 2903 for (int j = 0; j < guard_count; j++) { |
| 2904 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); |
| 2905 } |
| 2906 return alternative.node()->Emit(compiler, &out_of_line_variant); |
| 2907 } |
| 2908 } |
| 2909 |
| 2910 |
| 2179 bool ActionNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2911 bool ActionNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { |
| 2180 RegExpMacroAssembler* macro = compiler->macro_assembler(); | 2912 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2181 LimitResult limit_result = LimitVersions(compiler, variant); | 2913 LimitResult limit_result = LimitVersions(compiler, variant); |
| 2182 if (limit_result == DONE) return true; | 2914 if (limit_result == DONE) return true; |
| 2183 if (limit_result == FAIL) return false; | 2915 if (limit_result == FAIL) return false; |
| 2184 ASSERT(limit_result == CONTINUE); | 2916 ASSERT(limit_result == CONTINUE); |
| 2185 | 2917 |
| 2186 RecursionCheck rc(compiler); | 2918 RecursionCheck rc(compiler); |
| 2187 | 2919 |
| 2188 switch (type_) { | 2920 switch (type_) { |
| 2189 case STORE_POSITION: { | 2921 case STORE_POSITION: { |
| 2190 GenerationVariant::DeferredCapture | 2922 GenerationVariant::DeferredCapture |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2202 } | 2934 } |
| 2203 case SET_REGISTER: { | 2935 case SET_REGISTER: { |
| 2204 GenerationVariant::DeferredSetRegister | 2936 GenerationVariant::DeferredSetRegister |
| 2205 new_set(data_.u_store_register.reg, data_.u_store_register.value); | 2937 new_set(data_.u_store_register.reg, data_.u_store_register.value); |
| 2206 GenerationVariant new_variant = *variant; | 2938 GenerationVariant new_variant = *variant; |
| 2207 new_variant.add_action(&new_set); | 2939 new_variant.add_action(&new_set); |
| 2208 return on_success()->Emit(compiler, &new_variant); | 2940 return on_success()->Emit(compiler, &new_variant); |
| 2209 } | 2941 } |
| 2210 case BEGIN_SUBMATCH: | 2942 case BEGIN_SUBMATCH: |
| 2211 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 2943 if (!variant->is_trivial()) return variant->Flush(compiler, this); |
| 2212 macro->WriteCurrentPositionToRegister( | 2944 assembler->WriteCurrentPositionToRegister( |
| 2213 data_.u_submatch.current_position_register, 0); | 2945 data_.u_submatch.current_position_register, 0); |
| 2214 macro->WriteStackPointerToRegister( | 2946 assembler->WriteStackPointerToRegister( |
| 2215 data_.u_submatch.stack_pointer_register); | 2947 data_.u_submatch.stack_pointer_register); |
| 2216 return on_success()->Emit(compiler, variant); | 2948 return on_success()->Emit(compiler, variant); |
| 2217 case POSITIVE_SUBMATCH_SUCCESS: | 2949 case POSITIVE_SUBMATCH_SUCCESS: |
| 2218 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 2950 if (!variant->is_trivial()) return variant->Flush(compiler, this); |
| 2219 // TODO(erikcorry): Implement support. | 2951 // TODO(erikcorry): Implement support. |
| 2220 if (info()->follows_word_interest || | 2952 if (info()->follows_word_interest || |
| 2221 info()->follows_newline_interest || | 2953 info()->follows_newline_interest || |
| 2222 info()->follows_start_interest) { | 2954 info()->follows_start_interest) { |
| 2223 return false; | 2955 return false; |
| 2224 } | 2956 } |
| 2225 if (info()->at_end) { | 2957 if (info()->at_end) { |
| 2226 Label at_end; | 2958 Label at_end; |
| 2227 // Load current character jumps to the label if we are beyond the string | 2959 // Load current character jumps to the label if we are beyond the string |
| 2228 // end. | 2960 // end. |
| 2229 macro->LoadCurrentCharacter(0, &at_end); | 2961 assembler->LoadCurrentCharacter(0, &at_end); |
| 2230 macro->GoTo(variant->backtrack()); | 2962 assembler->GoTo(variant->backtrack()); |
| 2231 macro->Bind(&at_end); | 2963 assembler->Bind(&at_end); |
| 2232 } | 2964 } |
| 2233 macro->ReadCurrentPositionFromRegister( | 2965 assembler->ReadCurrentPositionFromRegister( |
| 2234 data_.u_submatch.current_position_register); | 2966 data_.u_submatch.current_position_register); |
| 2235 macro->ReadStackPointerFromRegister( | 2967 assembler->ReadStackPointerFromRegister( |
| 2236 data_.u_submatch.stack_pointer_register); | 2968 data_.u_submatch.stack_pointer_register); |
| 2237 return on_success()->Emit(compiler, variant); | 2969 return on_success()->Emit(compiler, variant); |
| 2238 default: | 2970 default: |
| 2239 UNREACHABLE(); | 2971 UNREACHABLE(); |
| 2240 return false; | 2972 return false; |
| 2241 } | 2973 } |
| 2242 } | 2974 } |
| 2243 | 2975 |
| 2244 | 2976 |
| 2245 bool BackReferenceNode::Emit(RegExpCompiler* compiler, | 2977 bool BackReferenceNode::Emit(RegExpCompiler* compiler, |
| 2246 GenerationVariant* variant) { | 2978 GenerationVariant* variant) { |
| 2247 RegExpMacroAssembler* macro = compiler->macro_assembler(); | 2979 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2248 if (!variant->is_trivial()) { | 2980 if (!variant->is_trivial()) { |
| 2249 return variant->Flush(compiler, this); | 2981 return variant->Flush(compiler, this); |
| 2250 } | 2982 } |
| 2251 | 2983 |
| 2252 LimitResult limit_result = LimitVersions(compiler, variant); | 2984 LimitResult limit_result = LimitVersions(compiler, variant); |
| 2253 if (limit_result == DONE) return true; | 2985 if (limit_result == DONE) return true; |
| 2254 if (limit_result == FAIL) return false; | 2986 if (limit_result == FAIL) return false; |
| 2255 ASSERT(limit_result == CONTINUE); | 2987 ASSERT(limit_result == CONTINUE); |
| 2256 | 2988 |
| 2257 RecursionCheck rc(compiler); | 2989 RecursionCheck rc(compiler); |
| 2258 | 2990 |
| 2259 ASSERT_EQ(start_reg_ + 1, end_reg_); | 2991 ASSERT_EQ(start_reg_ + 1, end_reg_); |
| 2260 if (info()->at_end) { | 2992 if (info()->at_end) { |
| 2261 // If we are constrained to match at the end of the input then succeed | 2993 // If we are constrained to match at the end of the input then succeed |
| 2262 // iff the back reference is empty. | 2994 // iff the back reference is empty. |
| 2263 macro->CheckNotRegistersEqual(start_reg_, end_reg_, variant->backtrack()); | 2995 assembler->CheckNotRegistersEqual(start_reg_, |
| 2996 end_reg_, |
| 2997 variant->backtrack()); |
| 2264 } else { | 2998 } else { |
| 2265 if (compiler->ignore_case()) { | 2999 if (compiler->ignore_case()) { |
| 2266 macro->CheckNotBackReferenceIgnoreCase(start_reg_, variant->backtrack()); | 3000 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, |
| 3001 variant->backtrack()); |
| 2267 } else { | 3002 } else { |
| 2268 macro->CheckNotBackReference(start_reg_, variant->backtrack()); | 3003 assembler->CheckNotBackReference(start_reg_, variant->backtrack()); |
| 2269 } | 3004 } |
| 2270 } | 3005 } |
| 2271 return on_success()->Emit(compiler, variant); | 3006 return on_success()->Emit(compiler, variant); |
| 2272 } | 3007 } |
| 2273 | 3008 |
| 2274 | 3009 |
| 2275 // ------------------------------------------------------------------- | 3010 // ------------------------------------------------------------------- |
| 2276 // Dot/dotty output | 3011 // Dot/dotty output |
| 2277 | 3012 |
| 2278 | 3013 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2417 | 3152 |
| 2418 void DotPrinter::PrintAttributes(RegExpNode* that) { | 3153 void DotPrinter::PrintAttributes(RegExpNode* that) { |
| 2419 stream()->Add(" a%p [shape=Mrecord, color=grey, fontcolor=grey, " | 3154 stream()->Add(" a%p [shape=Mrecord, color=grey, fontcolor=grey, " |
| 2420 "margin=0.1, fontsize=10, label=\"{", | 3155 "margin=0.1, fontsize=10, label=\"{", |
| 2421 that); | 3156 that); |
| 2422 AttributePrinter printer(this); | 3157 AttributePrinter printer(this); |
| 2423 NodeInfo* info = that->info(); | 3158 NodeInfo* info = that->info(); |
| 2424 printer.PrintBit("NI", info->follows_newline_interest); | 3159 printer.PrintBit("NI", info->follows_newline_interest); |
| 2425 printer.PrintBit("WI", info->follows_word_interest); | 3160 printer.PrintBit("WI", info->follows_word_interest); |
| 2426 printer.PrintBit("SI", info->follows_start_interest); | 3161 printer.PrintBit("SI", info->follows_start_interest); |
| 2427 printer.PrintBit("DN", info->determine_newline); | |
| 2428 printer.PrintBit("DW", info->determine_word); | |
| 2429 printer.PrintBit("DS", info->determine_start); | |
| 2430 printer.PrintBit("DDN", info->does_determine_newline); | |
| 2431 printer.PrintBit("DDW", info->does_determine_word); | |
| 2432 printer.PrintBit("DDS", info->does_determine_start); | |
| 2433 printer.PrintPositive("IW", info->is_word); | |
| 2434 printer.PrintPositive("IN", info->is_newline); | |
| 2435 printer.PrintPositive("FN", info->follows_newline); | |
| 2436 printer.PrintPositive("FW", info->follows_word); | |
| 2437 printer.PrintPositive("FS", info->follows_start); | |
| 2438 Label* label = that->label(); | 3162 Label* label = that->label(); |
| 2439 if (label->is_bound()) | 3163 if (label->is_bound()) |
| 2440 printer.PrintPositive("@", label->pos()); | 3164 printer.PrintPositive("@", label->pos()); |
| 2441 stream()->Add("}\"];\n"); | 3165 stream()->Add("}\"];\n"); |
| 2442 stream()->Add(" a%p -> n%p [style=dashed, color=grey, " | 3166 stream()->Add(" a%p -> n%p [style=dashed, color=grey, " |
| 2443 "arrowhead=none];\n", that, that); | 3167 "arrowhead=none];\n", that, that); |
| 2444 } | 3168 } |
| 2445 | 3169 |
| 2446 | 3170 |
| 2447 static const bool kPrintDispatchTable = false; | 3171 static const bool kPrintDispatchTable = false; |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2659 // | ` | 3383 // | ` |
| 2660 // | (x) | 3384 // | (x) |
| 2661 // v ^ | 3385 // v ^ |
| 2662 // (r=0)-->(?)---/ [if r < t] | 3386 // (r=0)-->(?)---/ [if r < t] |
| 2663 // | | 3387 // | |
| 2664 // [if r >= f] \----> ... | 3388 // [if r >= f] \----> ... |
| 2665 // | 3389 // |
| 2666 // | 3390 // |
| 2667 // TODO(someone): clear captures on repetition and handle empty | 3391 // TODO(someone): clear captures on repetition and handle empty |
| 2668 // matches. | 3392 // matches. |
| 3393 |
| 3394 // 15.10.2.5 RepeatMatcher algorithm. |
| 3395 // The parser has already eliminated the case where max is 0. In the case |
| 3396 // where max_match is zero the parser has removed the quantifier if min was |
| 3397 // > 0 and removed the atom if min was 0. See AddQuantifierToAtom. |
| 3398 |
| 3399 // If we know that we cannot match zero length then things are a little |
| 3400 // simpler since we don't need to make the special zero length match check |
| 3401 // from step 2.1. If the min and max are small we can unroll a little in |
| 3402 // this case. |
| 3403 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} |
| 3404 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} |
| 3405 if (max == 0) return on_success; // This can happen due to recursion. |
| 3406 if (body->min_match() > 0) { |
| 3407 if (min > 0 && min <= kMaxUnrolledMinMatches) { |
| 3408 int new_max = (max == kInfinity) ? max : max - min; |
| 3409 // Recurse once to get the loop or optional matches after the fixed ones. |
| 3410 RegExpNode* answer = |
| 3411 ToNode(0, new_max, is_greedy, body, compiler, on_success); |
| 3412 // Unroll the forced matches from 0 to min. This can cause chains of |
| 3413 // TextNodes (which the parser does not generate). These should be |
| 3414 // combined if it turns out they hinder good code generation. |
| 3415 for (int i = 0; i < min; i++) { |
| 3416 answer = body->ToNode(compiler, answer); |
| 3417 } |
| 3418 return answer; |
| 3419 } |
| 3420 if (max <= kMaxUnrolledMaxMatches) { |
| 3421 ASSERT(min == 0); |
| 3422 // Unroll the optional matches up to max. |
| 3423 RegExpNode* answer = on_success; |
| 3424 for (int i = 0; i < max; i++) { |
| 3425 ChoiceNode* alternation = new ChoiceNode(2); |
| 3426 if (is_greedy) { |
| 3427 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, |
| 3428 answer))); |
| 3429 alternation->AddAlternative(GuardedAlternative(on_success)); |
| 3430 } else { |
| 3431 alternation->AddAlternative(GuardedAlternative(on_success)); |
| 3432 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, |
| 3433 answer))); |
| 3434 } |
| 3435 answer = alternation; |
| 3436 } |
| 3437 return answer; |
| 3438 } |
| 3439 } |
| 2669 bool has_min = min > 0; | 3440 bool has_min = min > 0; |
| 2670 bool has_max = max < RegExpQuantifier::kInfinity; | 3441 bool has_max = max < RegExpTree::kInfinity; |
| 2671 bool needs_counter = has_min || has_max; | 3442 bool needs_counter = has_min || has_max; |
| 2672 int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1; | 3443 int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1; |
| 2673 ChoiceNode* center = new LoopChoiceNode(2); | 3444 LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0); |
| 2674 RegExpNode* loop_return = needs_counter | 3445 RegExpNode* loop_return = needs_counter |
| 2675 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) | 3446 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) |
| 2676 : static_cast<RegExpNode*>(center); | 3447 : static_cast<RegExpNode*>(center); |
| 2677 RegExpNode* body_node = body->ToNode(compiler, loop_return); | 3448 RegExpNode* body_node = body->ToNode(compiler, loop_return); |
| 2678 GuardedAlternative body_alt(body_node); | 3449 GuardedAlternative body_alt(body_node); |
| 2679 if (has_max) { | 3450 if (has_max) { |
| 2680 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max); | 3451 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max); |
| 2681 body_alt.AddGuard(body_guard); | 3452 body_alt.AddGuard(body_guard); |
| 2682 } | 3453 } |
| 2683 GuardedAlternative rest_alt(on_success); | 3454 GuardedAlternative rest_alt(on_success); |
| 2684 if (has_min) { | 3455 if (has_min) { |
| 2685 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min); | 3456 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min); |
| 2686 rest_alt.AddGuard(rest_guard); | 3457 rest_alt.AddGuard(rest_guard); |
| 2687 } | 3458 } |
| 2688 if (is_greedy) { | 3459 if (is_greedy) { |
| 2689 center->AddAlternative(body_alt); | 3460 center->AddLoopAlternative(body_alt); |
| 2690 center->AddAlternative(rest_alt); | 3461 center->AddContinueAlternative(rest_alt); |
| 2691 } else { | 3462 } else { |
| 2692 center->AddAlternative(rest_alt); | 3463 center->AddContinueAlternative(rest_alt); |
| 2693 center->AddAlternative(body_alt); | 3464 center->AddLoopAlternative(body_alt); |
| 2694 } | 3465 } |
| 2695 if (needs_counter) { | 3466 if (needs_counter) { |
| 2696 return ActionNode::SetRegister(reg_ctr, 0, center); | 3467 return ActionNode::SetRegister(reg_ctr, 0, center); |
| 2697 } else { | 3468 } else { |
| 2698 return center; | 3469 return center; |
| 2699 } | 3470 } |
| 2700 } | 3471 } |
| 2701 | 3472 |
| 2702 | 3473 |
| 2703 RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler, | 3474 RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler, |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3039 RegExpNode* sibling = siblings_.Get(i); | 3810 RegExpNode* sibling = siblings_.Get(i); |
| 3040 if (sibling->info()->Matches(info)) | 3811 if (sibling->info()->Matches(info)) |
| 3041 return sibling; | 3812 return sibling; |
| 3042 } | 3813 } |
| 3043 return NULL; | 3814 return NULL; |
| 3044 } | 3815 } |
| 3045 | 3816 |
| 3046 | 3817 |
| 3047 RegExpNode* RegExpNode::EnsureSibling(NodeInfo* info, bool* cloned) { | 3818 RegExpNode* RegExpNode::EnsureSibling(NodeInfo* info, bool* cloned) { |
| 3048 ASSERT_EQ(false, *cloned); | 3819 ASSERT_EQ(false, *cloned); |
| 3049 ASSERT(!info->HasAssertions()); | |
| 3050 siblings_.Ensure(this); | 3820 siblings_.Ensure(this); |
| 3051 RegExpNode* result = TryGetSibling(info); | 3821 RegExpNode* result = TryGetSibling(info); |
| 3052 if (result != NULL) return result; | 3822 if (result != NULL) return result; |
| 3053 result = this->Clone(); | 3823 result = this->Clone(); |
| 3054 NodeInfo* new_info = result->info(); | 3824 NodeInfo* new_info = result->info(); |
| 3055 new_info->ResetCompilationState(); | 3825 new_info->ResetCompilationState(); |
| 3056 new_info->AddFromPreceding(info); | 3826 new_info->AddFromPreceding(info); |
| 3057 AddSibling(result); | 3827 AddSibling(result); |
| 3058 *cloned = true; | 3828 *cloned = true; |
| 3059 return result; | 3829 return result; |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3271 return entry->out_set(); | 4041 return entry->out_set(); |
| 3272 else | 4042 else |
| 3273 return empty(); | 4043 return empty(); |
| 3274 } | 4044 } |
| 3275 | 4045 |
| 3276 | 4046 |
| 3277 // ------------------------------------------------------------------- | 4047 // ------------------------------------------------------------------- |
| 3278 // Analysis | 4048 // Analysis |
| 3279 | 4049 |
| 3280 | 4050 |
| 3281 void AssertionPropagation::EnsureAnalyzed(RegExpNode* that) { | 4051 void Analysis::EnsureAnalyzed(RegExpNode* that) { |
| 3282 if (that->info()->been_analyzed || that->info()->being_analyzed) | 4052 if (that->info()->been_analyzed || that->info()->being_analyzed) |
| 3283 return; | 4053 return; |
| 3284 that->info()->being_analyzed = true; | 4054 that->info()->being_analyzed = true; |
| 3285 that->Accept(this); | 4055 that->Accept(this); |
| 3286 that->info()->being_analyzed = false; | 4056 that->info()->being_analyzed = false; |
| 3287 that->info()->been_analyzed = true; | 4057 that->info()->been_analyzed = true; |
| 3288 } | 4058 } |
| 3289 | 4059 |
| 3290 | 4060 |
| 3291 void AssertionPropagation::VisitEnd(EndNode* that) { | 4061 void Analysis::VisitEnd(EndNode* that) { |
| 3292 // nothing to do | 4062 // nothing to do |
| 3293 } | 4063 } |
| 3294 | 4064 |
| 3295 | 4065 |
| 3296 void TextNode::CalculateOffsets() { | 4066 void TextNode::CalculateOffsets() { |
| 3297 int element_count = elements()->length(); | 4067 int element_count = elements()->length(); |
| 3298 // Set up the offsets of the elements relative to the start. This is a fixed | 4068 // Set up the offsets of the elements relative to the start. This is a fixed |
| 3299 // quantity since a TextNode can only contain fixed-width things. | 4069 // quantity since a TextNode can only contain fixed-width things. |
| 3300 int cp_offset = 0; | 4070 int cp_offset = 0; |
| 3301 for (int i = 0; i < element_count; i++) { | 4071 for (int i = 0; i < element_count; i++) { |
| 3302 TextElement& elm = elements()->at(i); | 4072 TextElement& elm = elements()->at(i); |
| 3303 elm.cp_offset = cp_offset; | 4073 elm.cp_offset = cp_offset; |
| 3304 if (elm.type == TextElement::ATOM) { | 4074 if (elm.type == TextElement::ATOM) { |
| 3305 cp_offset += elm.data.u_atom->data().length(); | 4075 cp_offset += elm.data.u_atom->data().length(); |
| 3306 } else { | 4076 } else { |
| 3307 cp_offset++; | 4077 cp_offset++; |
| 3308 Vector<const uc16> quarks = elm.data.u_atom->data(); | 4078 Vector<const uc16> quarks = elm.data.u_atom->data(); |
| 3309 } | 4079 } |
| 3310 } | 4080 } |
| 3311 } | 4081 } |
| 3312 | 4082 |
| 3313 | 4083 |
| 3314 void AssertionPropagation::VisitText(TextNode* that) { | 4084 void Analysis::VisitText(TextNode* that) { |
| 3315 if (ignore_case_) { | 4085 if (ignore_case_) { |
| 3316 that->MakeCaseIndependent(); | 4086 that->MakeCaseIndependent(); |
| 3317 } | 4087 } |
| 3318 EnsureAnalyzed(that->on_success()); | 4088 EnsureAnalyzed(that->on_success()); |
| 3319 NodeInfo* info = that->info(); | |
| 3320 NodeInfo* next_info = that->on_success()->info(); | |
| 3321 // If the following node is interested in what it follows then this | |
| 3322 // node must determine it. | |
| 3323 info->determine_newline = next_info->follows_newline_interest; | |
| 3324 info->determine_word = next_info->follows_word_interest; | |
| 3325 info->determine_start = next_info->follows_start_interest; | |
| 3326 that->CalculateOffsets(); | 4089 that->CalculateOffsets(); |
| 3327 } | 4090 } |
| 3328 | 4091 |
| 3329 | 4092 |
| 3330 void AssertionPropagation::VisitAction(ActionNode* that) { | 4093 void Analysis::VisitAction(ActionNode* that) { |
| 3331 RegExpNode* target = that->on_success(); | 4094 RegExpNode* target = that->on_success(); |
| 3332 EnsureAnalyzed(target); | 4095 EnsureAnalyzed(target); |
| 3333 // If the next node is interested in what it follows then this node | 4096 // If the next node is interested in what it follows then this node |
| 3334 // has to be interested too so it can pass the information on. | 4097 // has to be interested too so it can pass the information on. |
| 3335 that->info()->AddFromFollowing(target->info()); | 4098 that->info()->AddFromFollowing(target->info()); |
| 3336 } | 4099 } |
| 3337 | 4100 |
| 3338 | 4101 |
| 3339 void AssertionPropagation::VisitChoice(ChoiceNode* that) { | 4102 void Analysis::VisitChoice(ChoiceNode* that) { |
| 3340 NodeInfo* info = that->info(); | 4103 NodeInfo* info = that->info(); |
| 3341 for (int i = 0; i < that->alternatives()->length(); i++) { | 4104 for (int i = 0; i < that->alternatives()->length(); i++) { |
| 3342 RegExpNode* node = that->alternatives()->at(i).node(); | 4105 RegExpNode* node = that->alternatives()->at(i).node(); |
| 3343 EnsureAnalyzed(node); | 4106 EnsureAnalyzed(node); |
| 3344 // Anything the following nodes need to know has to be known by | 4107 // Anything the following nodes need to know has to be known by |
| 3345 // this node also, so it can pass it on. | 4108 // this node also, so it can pass it on. |
| 3346 info->AddFromFollowing(node->info()); | 4109 info->AddFromFollowing(node->info()); |
| 3347 } | 4110 } |
| 3348 } | 4111 } |
| 3349 | 4112 |
| 3350 | 4113 |
| 3351 void AssertionPropagation::VisitBackReference(BackReferenceNode* that) { | 4114 void Analysis::VisitLoopChoice(LoopChoiceNode* that) { |
| 3352 EnsureAnalyzed(that->on_success()); | 4115 NodeInfo* info = that->info(); |
| 4116 for (int i = 0; i < that->alternatives()->length(); i++) { |
| 4117 RegExpNode* node = that->alternatives()->at(i).node(); |
| 4118 if (node != that->loop_node()) { |
| 4119 EnsureAnalyzed(node); |
| 4120 info->AddFromFollowing(node->info()); |
| 4121 } |
| 4122 } |
| 4123 // Check the loop last since it may need the value of this node |
| 4124 // to get a correct result. |
| 4125 EnsureAnalyzed(that->loop_node()); |
| 4126 info->AddFromFollowing(that->loop_node()->info()); |
| 3353 } | 4127 } |
| 3354 | 4128 |
| 3355 | 4129 |
| 3356 // ------------------------------------------------------------------- | 4130 void Analysis::VisitBackReference(BackReferenceNode* that) { |
| 3357 // Assumption expansion | 4131 EnsureAnalyzed(that->on_success()); |
| 3358 | |
| 3359 | |
| 3360 RegExpNode* RegExpNode::EnsureExpanded(NodeInfo* info) { | |
| 3361 siblings_.Ensure(this); | |
| 3362 NodeInfo new_info = *this->info(); | |
| 3363 if (new_info.follows_word_interest) | |
| 3364 new_info.follows_word = info->follows_word; | |
| 3365 if (new_info.follows_newline_interest) | |
| 3366 new_info.follows_newline = info->follows_newline; | |
| 3367 // If the following node should determine something we need to get | |
| 3368 // a sibling that determines it. | |
| 3369 new_info.does_determine_newline = new_info.determine_newline; | |
| 3370 new_info.does_determine_word = new_info.determine_word; | |
| 3371 new_info.does_determine_start = new_info.determine_start; | |
| 3372 RegExpNode* sibling = TryGetSibling(&new_info); | |
| 3373 if (sibling == NULL) { | |
| 3374 sibling = ExpandLocal(&new_info); | |
| 3375 siblings_.Add(sibling); | |
| 3376 sibling->info()->being_expanded = true; | |
| 3377 sibling->ExpandChildren(); | |
| 3378 sibling->info()->being_expanded = false; | |
| 3379 sibling->info()->been_expanded = true; | |
| 3380 } else { | |
| 3381 NodeInfo* sib_info = sibling->info(); | |
| 3382 if (!sib_info->been_expanded && !sib_info->being_expanded) { | |
| 3383 sibling->info()->being_expanded = true; | |
| 3384 sibling->ExpandChildren(); | |
| 3385 sibling->info()->being_expanded = false; | |
| 3386 sibling->info()->been_expanded = true; | |
| 3387 } | |
| 3388 } | |
| 3389 return sibling; | |
| 3390 } | |
| 3391 | |
| 3392 | |
| 3393 RegExpNode* ChoiceNode::ExpandLocal(NodeInfo* info) { | |
| 3394 ChoiceNode* clone = this->Clone(); | |
| 3395 clone->info()->ResetCompilationState(); | |
| 3396 clone->info()->AddAssumptions(info); | |
| 3397 return clone; | |
| 3398 } | |
| 3399 | |
| 3400 | |
| 3401 void ChoiceNode::ExpandChildren() { | |
| 3402 ZoneList<GuardedAlternative>* alts = alternatives(); | |
| 3403 ZoneList<GuardedAlternative>* new_alts | |
| 3404 = new ZoneList<GuardedAlternative>(alts->length()); | |
| 3405 for (int i = 0; i < alts->length(); i++) { | |
| 3406 GuardedAlternative next = alts->at(i); | |
| 3407 next.set_node(next.node()->EnsureExpanded(info())); | |
| 3408 new_alts->Add(next); | |
| 3409 } | |
| 3410 alternatives_ = new_alts; | |
| 3411 } | |
| 3412 | |
| 3413 | |
| 3414 RegExpNode* TextNode::ExpandLocal(NodeInfo* info) { | |
| 3415 TextElement last = elements()->last(); | |
| 3416 if (last.type == TextElement::CHAR_CLASS) { | |
| 3417 RegExpCharacterClass* char_class = last.data.u_char_class; | |
| 3418 if (info->does_determine_word) { | |
| 3419 ZoneList<CharacterRange>* word = NULL; | |
| 3420 ZoneList<CharacterRange>* non_word = NULL; | |
| 3421 CharacterRange::Split(char_class->ranges(), | |
| 3422 CharacterRange::GetWordBounds(), | |
| 3423 &word, | |
| 3424 &non_word); | |
| 3425 if (non_word == NULL) { | |
| 3426 // This node contains no non-word characters so it must be | |
| 3427 // all word. | |
| 3428 this->info()->is_word = NodeInfo::TRUE; | |
| 3429 } else if (word == NULL) { | |
| 3430 // Vice versa. | |
| 3431 this->info()->is_word = NodeInfo::FALSE; | |
| 3432 } else { | |
| 3433 // If this character class contains both word and non-word | |
| 3434 // characters we need to split it into two. | |
| 3435 ChoiceNode* result = new ChoiceNode(2); | |
| 3436 // Welcome to the family, son! | |
| 3437 result->set_siblings(this->siblings()); | |
| 3438 *result->info() = *this->info(); | |
| 3439 result->info()->ResetCompilationState(); | |
| 3440 result->info()->AddAssumptions(info); | |
| 3441 RegExpNode* word_node | |
| 3442 = new TextNode(new RegExpCharacterClass(word, false), | |
| 3443 on_success()); | |
| 3444 word_node->info()->determine_word = true; | |
| 3445 word_node->info()->does_determine_word = true; | |
| 3446 word_node->info()->is_word = NodeInfo::TRUE; | |
| 3447 result->alternatives()->Add(GuardedAlternative(word_node)); | |
| 3448 RegExpNode* non_word_node | |
| 3449 = new TextNode(new RegExpCharacterClass(non_word, false), | |
| 3450 on_success()); | |
| 3451 non_word_node->info()->determine_word = true; | |
| 3452 non_word_node->info()->does_determine_word = true; | |
| 3453 non_word_node->info()->is_word = NodeInfo::FALSE; | |
| 3454 result->alternatives()->Add(GuardedAlternative(non_word_node)); | |
| 3455 return result; | |
| 3456 } | |
| 3457 } | |
| 3458 } | |
| 3459 TextNode* clone = this->Clone(); | |
| 3460 clone->info()->ResetCompilationState(); | |
| 3461 clone->info()->AddAssumptions(info); | |
| 3462 return clone; | |
| 3463 } | |
| 3464 | |
| 3465 | |
| 3466 void TextNode::ExpandAtomChildren(RegExpAtom* that) { | |
| 3467 NodeInfo new_info = *info(); | |
| 3468 uc16 last = that->data()[that->data().length() - 1]; | |
| 3469 if (info()->determine_word) { | |
| 3470 new_info.follows_word = IsRegExpWord(last) | |
| 3471 ? NodeInfo::TRUE : NodeInfo::FALSE; | |
| 3472 } else { | |
| 3473 new_info.follows_word = NodeInfo::UNKNOWN; | |
| 3474 } | |
| 3475 if (info()->determine_newline) { | |
| 3476 new_info.follows_newline = IsRegExpNewline(last) | |
| 3477 ? NodeInfo::TRUE : NodeInfo::FALSE; | |
| 3478 } else { | |
| 3479 new_info.follows_newline = NodeInfo::UNKNOWN; | |
| 3480 } | |
| 3481 if (info()->determine_start) { | |
| 3482 new_info.follows_start = NodeInfo::FALSE; | |
| 3483 } else { | |
| 3484 new_info.follows_start = NodeInfo::UNKNOWN; | |
| 3485 } | |
| 3486 set_on_success(on_success()->EnsureExpanded(&new_info)); | |
| 3487 } | |
| 3488 | |
| 3489 | |
| 3490 void TextNode::ExpandCharClassChildren(RegExpCharacterClass* that) { | |
| 3491 if (info()->does_determine_word) { | |
| 3492 // ASSERT(info()->is_word != NodeInfo::UNKNOWN); | |
| 3493 NodeInfo next_info = *on_success()->info(); | |
| 3494 next_info.follows_word = info()->is_word; | |
| 3495 set_on_success(on_success()->EnsureExpanded(&next_info)); | |
| 3496 } else { | |
| 3497 set_on_success(on_success()->EnsureExpanded(info())); | |
| 3498 } | |
| 3499 } | |
| 3500 | |
| 3501 | |
| 3502 void TextNode::ExpandChildren() { | |
| 3503 TextElement last = elements()->last(); | |
| 3504 switch (last.type) { | |
| 3505 case TextElement::ATOM: | |
| 3506 ExpandAtomChildren(last.data.u_atom); | |
| 3507 break; | |
| 3508 case TextElement::CHAR_CLASS: | |
| 3509 ExpandCharClassChildren(last.data.u_char_class); | |
| 3510 break; | |
| 3511 default: | |
| 3512 UNREACHABLE(); | |
| 3513 } | |
| 3514 } | |
| 3515 | |
| 3516 | |
| 3517 RegExpNode* ActionNode::ExpandLocal(NodeInfo* info) { | |
| 3518 ActionNode* clone = this->Clone(); | |
| 3519 clone->info()->ResetCompilationState(); | |
| 3520 clone->info()->AddAssumptions(info); | |
| 3521 return clone; | |
| 3522 } | |
| 3523 | |
| 3524 | |
| 3525 void ActionNode::ExpandChildren() { | |
| 3526 set_on_success(on_success()->EnsureExpanded(info())); | |
| 3527 } | |
| 3528 | |
| 3529 | |
| 3530 RegExpNode* BackReferenceNode::ExpandLocal(NodeInfo* info) { | |
| 3531 BackReferenceNode* clone = this->Clone(); | |
| 3532 clone->info()->ResetCompilationState(); | |
| 3533 clone->info()->AddAssumptions(info); | |
| 3534 return clone; | |
| 3535 } | |
| 3536 | |
| 3537 | |
| 3538 void BackReferenceNode::ExpandChildren() { | |
| 3539 set_on_success(on_success()->EnsureExpanded(info())); | |
| 3540 } | |
| 3541 | |
| 3542 | |
| 3543 RegExpNode* EndNode::ExpandLocal(NodeInfo* info) { | |
| 3544 EndNode* clone = this->Clone(); | |
| 3545 clone->info()->ResetCompilationState(); | |
| 3546 clone->info()->AddAssumptions(info); | |
| 3547 return clone; | |
| 3548 } | |
| 3549 | |
| 3550 | |
| 3551 void EndNode::ExpandChildren() { | |
| 3552 // nothing to do | |
| 3553 } | 4132 } |
| 3554 | 4133 |
| 3555 | 4134 |
| 3556 // ------------------------------------------------------------------- | 4135 // ------------------------------------------------------------------- |
| 3557 // Dispatch table construction | 4136 // Dispatch table construction |
| 3558 | 4137 |
| 3559 | 4138 |
| 3560 void DispatchTableConstructor::VisitEnd(EndNode* that) { | 4139 void DispatchTableConstructor::VisitEnd(EndNode* that) { |
| 3561 AddRange(CharacterRange::Everything()); | 4140 AddRange(CharacterRange::Everything()); |
| 3562 } | 4141 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3656 } | 4235 } |
| 3657 } | 4236 } |
| 3658 | 4237 |
| 3659 | 4238 |
| 3660 void DispatchTableConstructor::VisitAction(ActionNode* that) { | 4239 void DispatchTableConstructor::VisitAction(ActionNode* that) { |
| 3661 RegExpNode* target = that->on_success(); | 4240 RegExpNode* target = that->on_success(); |
| 3662 target->Accept(this); | 4241 target->Accept(this); |
| 3663 } | 4242 } |
| 3664 | 4243 |
| 3665 | 4244 |
| 3666 #ifdef DEBUG | |
| 3667 | |
| 3668 | |
| 3669 class VisitNodeScope { | |
| 3670 public: | |
| 3671 explicit VisitNodeScope(RegExpNode* node) : node_(node) { | |
| 3672 ASSERT(!node->info()->visited); | |
| 3673 node->info()->visited = true; | |
| 3674 } | |
| 3675 ~VisitNodeScope() { | |
| 3676 node_->info()->visited = false; | |
| 3677 } | |
| 3678 private: | |
| 3679 RegExpNode* node_; | |
| 3680 }; | |
| 3681 | |
| 3682 | |
| 3683 class NodeValidator : public NodeVisitor { | |
| 3684 public: | |
| 3685 virtual void ValidateInfo(NodeInfo* info) = 0; | |
| 3686 #define DECLARE_VISIT(Type) \ | |
| 3687 virtual void Visit##Type(Type##Node* that); | |
| 3688 FOR_EACH_NODE_TYPE(DECLARE_VISIT) | |
| 3689 #undef DECLARE_VISIT | |
| 3690 }; | |
| 3691 | |
| 3692 | |
| 3693 class PostAnalysisNodeValidator : public NodeValidator { | |
| 3694 public: | |
| 3695 virtual void ValidateInfo(NodeInfo* info); | |
| 3696 }; | |
| 3697 | |
| 3698 | |
| 3699 class PostExpansionNodeValidator : public NodeValidator { | |
| 3700 public: | |
| 3701 virtual void ValidateInfo(NodeInfo* info); | |
| 3702 }; | |
| 3703 | |
| 3704 | |
| 3705 void PostAnalysisNodeValidator::ValidateInfo(NodeInfo* info) { | |
| 3706 ASSERT(info->been_analyzed); | |
| 3707 } | |
| 3708 | |
| 3709 | |
| 3710 void PostExpansionNodeValidator::ValidateInfo(NodeInfo* info) { | |
| 3711 ASSERT_EQ(info->determine_newline, info->does_determine_newline); | |
| 3712 ASSERT_EQ(info->determine_start, info->does_determine_start); | |
| 3713 ASSERT_EQ(info->determine_word, info->does_determine_word); | |
| 3714 ASSERT_EQ(info->follows_word_interest, | |
| 3715 (info->follows_word != NodeInfo::UNKNOWN)); | |
| 3716 if (false) { | |
| 3717 // These are still unimplemented. | |
| 3718 ASSERT_EQ(info->follows_start_interest, | |
| 3719 (info->follows_start != NodeInfo::UNKNOWN)); | |
| 3720 ASSERT_EQ(info->follows_newline_interest, | |
| 3721 (info->follows_newline != NodeInfo::UNKNOWN)); | |
| 3722 } | |
| 3723 } | |
| 3724 | |
| 3725 | |
| 3726 void NodeValidator::VisitAction(ActionNode* that) { | |
| 3727 if (that->info()->visited) return; | |
| 3728 VisitNodeScope scope(that); | |
| 3729 ValidateInfo(that->info()); | |
| 3730 that->on_success()->Accept(this); | |
| 3731 } | |
| 3732 | |
| 3733 | |
| 3734 void NodeValidator::VisitBackReference(BackReferenceNode* that) { | |
| 3735 if (that->info()->visited) return; | |
| 3736 VisitNodeScope scope(that); | |
| 3737 ValidateInfo(that->info()); | |
| 3738 that->on_success()->Accept(this); | |
| 3739 } | |
| 3740 | |
| 3741 | |
| 3742 void NodeValidator::VisitChoice(ChoiceNode* that) { | |
| 3743 if (that->info()->visited) return; | |
| 3744 VisitNodeScope scope(that); | |
| 3745 ValidateInfo(that->info()); | |
| 3746 ZoneList<GuardedAlternative>* alts = that->alternatives(); | |
| 3747 for (int i = 0; i < alts->length(); i++) | |
| 3748 alts->at(i).node()->Accept(this); | |
| 3749 } | |
| 3750 | |
| 3751 | |
| 3752 void NodeValidator::VisitEnd(EndNode* that) { | |
| 3753 if (that->info()->visited) return; | |
| 3754 VisitNodeScope scope(that); | |
| 3755 ValidateInfo(that->info()); | |
| 3756 } | |
| 3757 | |
| 3758 | |
| 3759 void NodeValidator::VisitText(TextNode* that) { | |
| 3760 if (that->info()->visited) return; | |
| 3761 VisitNodeScope scope(that); | |
| 3762 ValidateInfo(that->info()); | |
| 3763 that->on_success()->Accept(this); | |
| 3764 } | |
| 3765 | |
| 3766 | |
| 3767 #endif | |
| 3768 | |
| 3769 | |
| 3770 Handle<FixedArray> RegExpEngine::Compile(RegExpCompileData* data, | 4245 Handle<FixedArray> RegExpEngine::Compile(RegExpCompileData* data, |
| 3771 bool ignore_case, | 4246 bool ignore_case, |
| 3772 bool is_multiline, | 4247 bool is_multiline, |
| 3773 Handle<String> pattern, | 4248 Handle<String> pattern, |
| 3774 bool is_ascii) { | 4249 bool is_ascii) { |
| 3775 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); | 4250 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); |
| 3776 // Wrap the body of the regexp in capture #0. | 4251 // Wrap the body of the regexp in capture #0. |
| 3777 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, | 4252 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, |
| 3778 0, | 4253 0, |
| 3779 &compiler, | 4254 &compiler, |
| 3780 compiler.accept()); | 4255 compiler.accept()); |
| 3781 // Add a .*? at the beginning, outside the body capture. | 4256 // Add a .*? at the beginning, outside the body capture. |
| 3782 // Note: We could choose to not add this if the regexp is anchored at | 4257 // Note: We could choose to not add this if the regexp is anchored at |
| 3783 // the start of the input but I'm not sure how best to do that and | 4258 // the start of the input but I'm not sure how best to do that and |
| 3784 // since we don't even handle ^ yet I'm saving that optimization for | 4259 // since we don't even handle ^ yet I'm saving that optimization for |
| 3785 // later. | 4260 // later. |
| 3786 RegExpNode* node = RegExpQuantifier::ToNode(0, | 4261 RegExpNode* node = RegExpQuantifier::ToNode(0, |
| 3787 RegExpQuantifier::kInfinity, | 4262 RegExpTree::kInfinity, |
| 3788 false, | 4263 false, |
| 3789 new RegExpCharacterClass('*'), | 4264 new RegExpCharacterClass('*'), |
| 3790 &compiler, | 4265 &compiler, |
| 3791 captured_body); | 4266 captured_body); |
| 3792 AssertionPropagation analysis(ignore_case); | 4267 data->node = node; |
| 4268 Analysis analysis(ignore_case); |
| 3793 analysis.EnsureAnalyzed(node); | 4269 analysis.EnsureAnalyzed(node); |
| 3794 | 4270 |
| 3795 NodeInfo info = *node->info(); | 4271 NodeInfo info = *node->info(); |
| 3796 data->has_lookbehind = info.HasLookbehind(); | |
| 3797 if (data->has_lookbehind) { | |
| 3798 // If this node needs information about the preceding text we let | |
| 3799 // it start with a character class that consumes a single character | |
| 3800 // and proceeds to wherever is appropriate. This means that if | |
| 3801 // has_lookbehind is set the code generator must start one character | |
| 3802 // before the start position. | |
| 3803 node = new TextNode(new RegExpCharacterClass('*'), node); | |
| 3804 analysis.EnsureAnalyzed(node); | |
| 3805 } | |
| 3806 | |
| 3807 #ifdef DEBUG | |
| 3808 PostAnalysisNodeValidator post_analysis_validator; | |
| 3809 node->Accept(&post_analysis_validator); | |
| 3810 #endif | |
| 3811 | |
| 3812 node = node->EnsureExpanded(&info); | |
| 3813 | |
| 3814 #ifdef DEBUG | |
| 3815 PostExpansionNodeValidator post_expansion_validator; | |
| 3816 node->Accept(&post_expansion_validator); | |
| 3817 #endif | |
| 3818 | |
| 3819 data->node = node; | |
| 3820 | 4272 |
| 3821 if (is_multiline && !FLAG_attempt_multiline_irregexp) { | 4273 if (is_multiline && !FLAG_attempt_multiline_irregexp) { |
| 3822 return Handle<FixedArray>::null(); | 4274 return Handle<FixedArray>::null(); |
| 3823 } | 4275 } |
| 3824 | 4276 |
| 3825 if (data->has_lookbehind) { | |
| 3826 return Handle<FixedArray>::null(); | |
| 3827 } | |
| 3828 | |
| 3829 if (FLAG_irregexp_native) { | 4277 if (FLAG_irregexp_native) { |
| 3830 #ifdef ARM | 4278 #ifdef ARM |
| 3831 // Unimplemented, fall-through to bytecode implementation. | 4279 // Unimplemented, fall-through to bytecode implementation. |
| 3832 #else // IA32 | 4280 #else // IA32 |
| 3833 RegExpMacroAssemblerIA32::Mode mode; | 4281 RegExpMacroAssemblerIA32::Mode mode; |
| 3834 if (is_ascii) { | 4282 if (is_ascii) { |
| 3835 mode = RegExpMacroAssemblerIA32::ASCII; | 4283 mode = RegExpMacroAssemblerIA32::ASCII; |
| 3836 } else { | 4284 } else { |
| 3837 mode = RegExpMacroAssemblerIA32::UC16; | 4285 mode = RegExpMacroAssemblerIA32::UC16; |
| 3838 } | 4286 } |
| 3839 RegExpMacroAssemblerIA32 macro_assembler(mode, | 4287 RegExpMacroAssemblerIA32 macro_assembler(mode, |
| 3840 (data->capture_count + 1) * 2); | 4288 (data->capture_count + 1) * 2); |
| 3841 return compiler.Assemble(¯o_assembler, | 4289 return compiler.Assemble(¯o_assembler, |
| 3842 node, | 4290 node, |
| 3843 data->capture_count, | 4291 data->capture_count, |
| 3844 pattern); | 4292 pattern); |
| 3845 #endif | 4293 #endif |
| 3846 } | 4294 } |
| 3847 EmbeddedVector<byte, 1024> codes; | 4295 EmbeddedVector<byte, 1024> codes; |
| 3848 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4296 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 3849 return compiler.Assemble(¯o_assembler, | 4297 return compiler.Assemble(¯o_assembler, |
| 3850 node, | 4298 node, |
| 3851 data->capture_count, | 4299 data->capture_count, |
| 3852 pattern); | 4300 pattern); |
| 3853 } | 4301 } |
| 3854 | 4302 |
| 3855 | 4303 |
| 3856 }} // namespace v8::internal | 4304 }} // namespace v8::internal |
| OLD | NEW |