| 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 22 matching lines...) Expand all Loading... |
| 33 #include "jsregexp-inl.h" | 33 #include "jsregexp-inl.h" |
| 34 #include "platform.h" | 34 #include "platform.h" |
| 35 #include "runtime.h" | 35 #include "runtime.h" |
| 36 #include "top.h" | 36 #include "top.h" |
| 37 #include "compilation-cache.h" | 37 #include "compilation-cache.h" |
| 38 #include "string-stream.h" | 38 #include "string-stream.h" |
| 39 #include "parser.h" | 39 #include "parser.h" |
| 40 #include "regexp-macro-assembler.h" | 40 #include "regexp-macro-assembler.h" |
| 41 #include "regexp-macro-assembler-tracer.h" | 41 #include "regexp-macro-assembler-tracer.h" |
| 42 #include "regexp-macro-assembler-irregexp.h" | 42 #include "regexp-macro-assembler-irregexp.h" |
| 43 #include "regexp-stack.h" |
| 43 | 44 |
| 44 #ifdef ARM | 45 #ifdef ARM |
| 45 #include "regexp-macro-assembler-arm.h" | 46 #include "regexp-macro-assembler-arm.h" |
| 46 #else // IA32 | 47 #else // IA32 |
| 47 #include "macro-assembler-ia32.h" | 48 #include "macro-assembler-ia32.h" |
| 48 #include "regexp-macro-assembler-ia32.h" | 49 #include "regexp-macro-assembler-ia32.h" |
| 49 #endif | 50 #endif |
| 50 | 51 |
| 51 #include "interpreter-irregexp.h" | 52 #include "interpreter-irregexp.h" |
| 52 | 53 |
| (...skipping 853 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 906 const byte* address; | 907 const byte* address; |
| 907 if (is_ascii) { | 908 if (is_ascii) { |
| 908 ExternalAsciiString* ext = ExternalAsciiString::cast(*subject); | 909 ExternalAsciiString* ext = ExternalAsciiString::cast(*subject); |
| 909 address = reinterpret_cast<const byte*>(ext->resource()->data()); | 910 address = reinterpret_cast<const byte*>(ext->resource()->data()); |
| 910 } else { | 911 } else { |
| 911 ExternalTwoByteString* ext = ExternalTwoByteString::cast(*subject); | 912 ExternalTwoByteString* ext = ExternalTwoByteString::cast(*subject); |
| 912 address = reinterpret_cast<const byte*>(ext->resource()->data()); | 913 address = reinterpret_cast<const byte*>(ext->resource()->data()); |
| 913 } | 914 } |
| 914 res = RegExpMacroAssemblerIA32::Execute( | 915 res = RegExpMacroAssemblerIA32::Execute( |
| 915 *code, | 916 *code, |
| 916 &address, | 917 const_cast<Address*>(&address), |
| 917 start_offset << char_size_shift, | 918 start_offset << char_size_shift, |
| 918 end_offset << char_size_shift, | 919 end_offset << char_size_shift, |
| 919 offsets_vector, | 920 offsets_vector, |
| 920 previous_index == 0); | 921 previous_index == 0); |
| 921 } else { // Sequential string | 922 } else { // Sequential string |
| 922 Address char_address = | 923 Address char_address = |
| 923 is_ascii ? SeqAsciiString::cast(*subject)->GetCharsAddress() | 924 is_ascii ? SeqAsciiString::cast(*subject)->GetCharsAddress() |
| 924 : SeqTwoByteString::cast(*subject)->GetCharsAddress(); | 925 : SeqTwoByteString::cast(*subject)->GetCharsAddress(); |
| 925 int byte_offset = char_address - reinterpret_cast<Address>(*subject); | 926 int byte_offset = char_address - reinterpret_cast<Address>(*subject); |
| 926 res = RegExpMacroAssemblerIA32::Execute( | 927 res = RegExpMacroAssemblerIA32::Execute( |
| 927 *code, | 928 *code, |
| 928 subject.location(), | 929 reinterpret_cast<Address*>(subject.location()), |
| 929 byte_offset + (start_offset << char_size_shift), | 930 byte_offset + (start_offset << char_size_shift), |
| 930 byte_offset + (end_offset << char_size_shift), | 931 byte_offset + (end_offset << char_size_shift), |
| 931 offsets_vector, | 932 offsets_vector, |
| 932 previous_index == 0); | 933 previous_index == 0); |
| 933 } | 934 } |
| 934 | 935 |
| 935 if (res == RegExpMacroAssemblerIA32::EXCEPTION) { | 936 if (res == RegExpMacroAssemblerIA32::EXCEPTION) { |
| 936 ASSERT(Top::has_pending_exception()); | 937 ASSERT(Top::has_pending_exception()); |
| 937 return Handle<Object>::null(); | 938 return Handle<Object>::null(); |
| 938 } | 939 } |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1102 // space. | 1103 // space. |
| 1103 // * The current state is virtualized. | 1104 // * The current state is virtualized. |
| 1104 // This is used to defer expensive operations until it is clear that they | 1105 // This is used to defer expensive operations until it is clear that they |
| 1105 // are needed and to generate code for a node more than once, allowing | 1106 // are needed and to generate code for a node more than once, allowing |
| 1106 // specialized an efficient versions of the code to be created. This is | 1107 // specialized an efficient versions of the code to be created. This is |
| 1107 // explained in the section below. | 1108 // explained in the section below. |
| 1108 // | 1109 // |
| 1109 // Execution state virtualization. | 1110 // Execution state virtualization. |
| 1110 // | 1111 // |
| 1111 // Instead of emitting code, nodes that manipulate the state can record their | 1112 // Instead of emitting code, nodes that manipulate the state can record their |
| 1112 // manipulation in an object called the GenerationVariant. The | 1113 // manipulation in an object called the Trace. The Trace object can record a |
| 1113 // GenerationVariant object can record a current position offset, an | 1114 // current position offset, an optional backtrack code location on the top of |
| 1114 // optional backtrack code location on the top of the virtualized backtrack | 1115 // the virtualized backtrack stack and some register changes. When a node is |
| 1115 // stack and some register changes. When a node is to be emitted it can flush | 1116 // to be emitted it can flush the Trace or update it. Flushing the Trace |
| 1116 // the GenerationVariant or update it. Flushing the GenerationVariant | |
| 1117 // will emit code to bring the actual state into line with the virtual state. | 1117 // will emit code to bring the actual state into line with the virtual state. |
| 1118 // Avoiding flushing the state can postpone some work (eg updates of capture | 1118 // Avoiding flushing the state can postpone some work (eg updates of capture |
| 1119 // registers). Postponing work can save time when executing the regular | 1119 // registers). Postponing work can save time when executing the regular |
| 1120 // expression since it may be found that the work never has to be done as a | 1120 // expression since it may be found that the work never has to be done as a |
| 1121 // failure to match can occur. In addition it is much faster to jump to a | 1121 // failure to match can occur. In addition it is much faster to jump to a |
| 1122 // known backtrack code location than it is to pop an unknown backtrack | 1122 // known backtrack code location than it is to pop an unknown backtrack |
| 1123 // location from the stack and jump there. | 1123 // location from the stack and jump there. |
| 1124 // | 1124 // |
| 1125 // The virtual state found in the GenerationVariant affects code generation. | 1125 // The virtual state found in the Trace affects code generation. For example |
| 1126 // For example the virtual state contains the difference between the actual | 1126 // the virtual state contains the difference between the actual current |
| 1127 // current position and the virtual current position, and matching code needs | 1127 // position and the virtual current position, and matching code needs to use |
| 1128 // to use this offset to attempt a match in the correct location of the input | 1128 // this offset to attempt a match in the correct location of the input |
| 1129 // string. Therefore code generated for a non-trivial GenerationVariant is | 1129 // string. Therefore code generated for a non-trivial trace is specialized |
| 1130 // specialized to that GenerationVariant. The code generator therefore | 1130 // to that trace. The code generator therefore has the ability to generate |
| 1131 // has the ability to generate code for each node several times. In order to | 1131 // code for each node several times. In order to limit the size of the |
| 1132 // limit the size of the generated code there is an arbitrary limit on how | 1132 // generated code there is an arbitrary limit on how many specialized sets of |
| 1133 // many specialized sets of code may be generated for a given node. If the | 1133 // code may be generated for a given node. If the limit is reached, the |
| 1134 // limit is reached, the GenerationVariant is flushed and a generic version of | 1134 // trace is flushed and a generic version of the code for a node is emitted. |
| 1135 // the code for a node is emitted. This is subsequently used for that node. | 1135 // This is subsequently used for that node. The code emitted for non-generic |
| 1136 // The code emitted for non-generic GenerationVariants is not recorded in the | 1136 // trace is not recorded in the node and so it cannot currently be reused in |
| 1137 // node and so it cannot currently be reused in the event that code generation | 1137 // the event that code generation is requested for an identical trace. |
| 1138 // is requested for an identical GenerationVariant. | |
| 1139 | 1138 |
| 1140 | 1139 |
| 1141 void RegExpTree::AppendToText(RegExpText* text) { | 1140 void RegExpTree::AppendToText(RegExpText* text) { |
| 1142 UNREACHABLE(); | 1141 UNREACHABLE(); |
| 1143 } | 1142 } |
| 1144 | 1143 |
| 1145 | 1144 |
| 1146 void RegExpAtom::AppendToText(RegExpText* text) { | 1145 void RegExpAtom::AppendToText(RegExpText* text) { |
| 1147 text->AddElement(TextElement::Atom(this)); | 1146 text->AddElement(TextElement::Atom(this)); |
| 1148 } | 1147 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1215 EndNode* accept() { return accept_; } | 1214 EndNode* accept() { return accept_; } |
| 1216 | 1215 |
| 1217 static const int kMaxRecursion = 100; | 1216 static const int kMaxRecursion = 100; |
| 1218 inline int recursion_depth() { return recursion_depth_; } | 1217 inline int recursion_depth() { return recursion_depth_; } |
| 1219 inline void IncrementRecursionDepth() { recursion_depth_++; } | 1218 inline void IncrementRecursionDepth() { recursion_depth_++; } |
| 1220 inline void DecrementRecursionDepth() { recursion_depth_--; } | 1219 inline void DecrementRecursionDepth() { recursion_depth_--; } |
| 1221 | 1220 |
| 1222 inline bool ignore_case() { return ignore_case_; } | 1221 inline bool ignore_case() { return ignore_case_; } |
| 1223 inline bool ascii() { return ascii_; } | 1222 inline bool ascii() { return ascii_; } |
| 1224 | 1223 |
| 1224 static const int kNoRegister = -1; |
| 1225 private: | 1225 private: |
| 1226 EndNode* accept_; | 1226 EndNode* accept_; |
| 1227 int next_register_; | 1227 int next_register_; |
| 1228 List<RegExpNode*>* work_list_; | 1228 List<RegExpNode*>* work_list_; |
| 1229 int recursion_depth_; | 1229 int recursion_depth_; |
| 1230 RegExpMacroAssembler* macro_assembler_; | 1230 RegExpMacroAssembler* macro_assembler_; |
| 1231 bool ignore_case_; | 1231 bool ignore_case_; |
| 1232 bool ascii_; | 1232 bool ascii_; |
| 1233 }; | 1233 }; |
| 1234 | 1234 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1264 #ifdef DEBUG | 1264 #ifdef DEBUG |
| 1265 if (FLAG_trace_regexp_assembler) | 1265 if (FLAG_trace_regexp_assembler) |
| 1266 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); | 1266 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); |
| 1267 else | 1267 else |
| 1268 #endif | 1268 #endif |
| 1269 macro_assembler_ = macro_assembler; | 1269 macro_assembler_ = macro_assembler; |
| 1270 List <RegExpNode*> work_list(0); | 1270 List <RegExpNode*> work_list(0); |
| 1271 work_list_ = &work_list; | 1271 work_list_ = &work_list; |
| 1272 Label fail; | 1272 Label fail; |
| 1273 macro_assembler->PushBacktrack(&fail); | 1273 macro_assembler->PushBacktrack(&fail); |
| 1274 GenerationVariant generic_variant; | 1274 Trace new_trace; |
| 1275 if (!start->Emit(this, &generic_variant)) { | 1275 if (!start->Emit(this, &new_trace)) { |
| 1276 fail.Unuse(); | 1276 fail.Unuse(); |
| 1277 return Handle<FixedArray>::null(); | 1277 return Handle<FixedArray>::null(); |
| 1278 } | 1278 } |
| 1279 macro_assembler_->Bind(&fail); | 1279 macro_assembler_->Bind(&fail); |
| 1280 macro_assembler_->Fail(); | 1280 macro_assembler_->Fail(); |
| 1281 while (!work_list.is_empty()) { | 1281 while (!work_list.is_empty()) { |
| 1282 if (!work_list.RemoveLast()->Emit(this, &generic_variant)) { | 1282 if (!work_list.RemoveLast()->Emit(this, &new_trace)) { |
| 1283 return Handle<FixedArray>::null(); | 1283 return Handle<FixedArray>::null(); |
| 1284 } | 1284 } |
| 1285 } | 1285 } |
| 1286 Handle<FixedArray> array = | 1286 Handle<FixedArray> array = |
| 1287 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); | 1287 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); |
| 1288 array->set(RegExpImpl::kIrregexpImplementationIndex, | 1288 array->set(RegExpImpl::kIrregexpImplementationIndex, |
| 1289 Smi::FromInt(macro_assembler_->Implementation())); | 1289 Smi::FromInt(macro_assembler_->Implementation())); |
| 1290 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, | 1290 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, |
| 1291 Smi::FromInt(next_register_)); | 1291 Smi::FromInt(next_register_)); |
| 1292 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, | 1292 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, |
| 1293 Smi::FromInt(capture_count)); | 1293 Smi::FromInt(capture_count)); |
| 1294 Handle<Object> code = macro_assembler_->GetCode(pattern); | 1294 Handle<Object> code = macro_assembler_->GetCode(pattern); |
| 1295 array->set(RegExpImpl::kIrregexpCodeIndex, *code); | 1295 array->set(RegExpImpl::kIrregexpCodeIndex, *code); |
| 1296 work_list_ = NULL; | 1296 work_list_ = NULL; |
| 1297 #ifdef DEBUG | 1297 #ifdef DEBUG |
| 1298 if (FLAG_trace_regexp_assembler) { | 1298 if (FLAG_trace_regexp_assembler) { |
| 1299 delete macro_assembler_; | 1299 delete macro_assembler_; |
| 1300 } | 1300 } |
| 1301 #endif | 1301 #endif |
| 1302 return array; | 1302 return array; |
| 1303 } | 1303 } |
| 1304 | 1304 |
| 1305 bool Trace::DeferredAction::Mentions(int that) { |
| 1306 if (type() == ActionNode::CLEAR_CAPTURES) { |
| 1307 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); |
| 1308 return range.Contains(that); |
| 1309 } else { |
| 1310 return reg() == that; |
| 1311 } |
| 1312 } |
| 1305 | 1313 |
| 1306 bool GenerationVariant::mentions_reg(int reg) { | 1314 |
| 1315 bool Trace::mentions_reg(int reg) { |
| 1307 for (DeferredAction* action = actions_; | 1316 for (DeferredAction* action = actions_; |
| 1308 action != NULL; | 1317 action != NULL; |
| 1309 action = action->next()) { | 1318 action = action->next()) { |
| 1310 if (reg == action->reg()) return true; | 1319 if (action->Mentions(reg)) |
| 1320 return true; |
| 1311 } | 1321 } |
| 1312 return false; | 1322 return false; |
| 1313 } | 1323 } |
| 1314 | 1324 |
| 1315 | 1325 |
| 1316 int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) { | 1326 bool Trace::GetStoredPosition(int reg, int* cp_offset) { |
| 1317 int max_register = -1; | 1327 ASSERT_EQ(0, *cp_offset); |
| 1318 for (DeferredAction* action = actions_; | 1328 for (DeferredAction* action = actions_; |
| 1319 action != NULL; | 1329 action != NULL; |
| 1320 action = action->next()) { | 1330 action = action->next()) { |
| 1321 affected_registers->Set(action->reg()); | 1331 if (action->Mentions(reg)) { |
| 1322 if (action->reg() > max_register) max_register = action->reg(); | 1332 if (action->type() == ActionNode::STORE_POSITION) { |
| 1333 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); |
| 1334 return true; |
| 1335 } else { |
| 1336 return false; |
| 1337 } |
| 1338 } |
| 1339 } |
| 1340 return false; |
| 1341 } |
| 1342 |
| 1343 |
| 1344 int Trace::FindAffectedRegisters(OutSet* affected_registers) { |
| 1345 int max_register = RegExpCompiler::kNoRegister; |
| 1346 for (DeferredAction* action = actions_; |
| 1347 action != NULL; |
| 1348 action = action->next()) { |
| 1349 if (action->type() == ActionNode::CLEAR_CAPTURES) { |
| 1350 Interval range = static_cast<DeferredClearCaptures*>(action)->range(); |
| 1351 for (int i = range.from(); i <= range.to(); i++) |
| 1352 affected_registers->Set(i); |
| 1353 if (range.to() > max_register) max_register = range.to(); |
| 1354 } else { |
| 1355 affected_registers->Set(action->reg()); |
| 1356 if (action->reg() > max_register) max_register = action->reg(); |
| 1357 } |
| 1323 } | 1358 } |
| 1324 return max_register; | 1359 return max_register; |
| 1325 } | 1360 } |
| 1326 | 1361 |
| 1327 | 1362 |
| 1328 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler, | 1363 void Trace::PushAffectedRegisters(RegExpMacroAssembler* assembler, |
| 1329 int max_register, | 1364 int max_register, |
| 1330 OutSet& affected_registers) { | 1365 OutSet& affected_registers) { |
| 1331 for (int reg = 0; reg <= max_register; reg++) { | 1366 // Stay safe and check every half times the limit. |
| 1332 if (affected_registers.Get(reg)) assembler->PushRegister(reg); | 1367 // (Round up in case the limit is 1). |
| 1368 int push_limit = (assembler->stack_limit_slack() + 1) / 2; |
| 1369 for (int reg = 0, pushes = 0; reg <= max_register; reg++) { |
| 1370 if (affected_registers.Get(reg)) { |
| 1371 pushes++; |
| 1372 RegExpMacroAssembler::StackCheckFlag check_stack_limit = |
| 1373 (pushes % push_limit) == 0 ? |
| 1374 RegExpMacroAssembler::kCheckStackLimit : |
| 1375 RegExpMacroAssembler::kNoStackLimitCheck; |
| 1376 assembler->PushRegister(reg, check_stack_limit); |
| 1377 } |
| 1333 } | 1378 } |
| 1334 } | 1379 } |
| 1335 | 1380 |
| 1336 | 1381 |
| 1337 void GenerationVariant::RestoreAffectedRegisters( | 1382 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler, |
| 1338 RegExpMacroAssembler* assembler, | 1383 int max_register, |
| 1339 int max_register, | 1384 OutSet& affected_registers) { |
| 1340 OutSet& affected_registers) { | |
| 1341 for (int reg = max_register; reg >= 0; reg--) { | 1385 for (int reg = max_register; reg >= 0; reg--) { |
| 1342 if (affected_registers.Get(reg)) assembler->PopRegister(reg); | 1386 if (affected_registers.Get(reg)) assembler->PopRegister(reg); |
| 1343 } | 1387 } |
| 1344 } | 1388 } |
| 1345 | 1389 |
| 1346 | 1390 |
| 1347 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* assembler, | 1391 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler, |
| 1348 int max_register, | 1392 int max_register, |
| 1349 OutSet& affected_registers) { | 1393 OutSet& affected_registers) { |
| 1350 for (int reg = 0; reg <= max_register; reg++) { | 1394 for (int reg = 0; reg <= max_register; reg++) { |
| 1351 if (!affected_registers.Get(reg)) { | 1395 if (!affected_registers.Get(reg)) { |
| 1352 continue; | 1396 continue; |
| 1353 } | 1397 } |
| 1354 int value = 0; | 1398 int value = 0; |
| 1355 bool absolute = false; | 1399 bool absolute = false; |
| 1400 bool clear = false; |
| 1356 int store_position = -1; | 1401 int store_position = -1; |
| 1357 // This is a little tricky because we are scanning the actions in reverse | 1402 // This is a little tricky because we are scanning the actions in reverse |
| 1358 // historical order (newest first). | 1403 // historical order (newest first). |
| 1359 for (DeferredAction* action = actions_; | 1404 for (DeferredAction* action = actions_; |
| 1360 action != NULL; | 1405 action != NULL; |
| 1361 action = action->next()) { | 1406 action = action->next()) { |
| 1362 if (action->reg() == reg) { | 1407 if (action->Mentions(reg)) { |
| 1363 switch (action->type()) { | 1408 switch (action->type()) { |
| 1364 case ActionNode::SET_REGISTER: { | 1409 case ActionNode::SET_REGISTER: { |
| 1365 GenerationVariant::DeferredSetRegister* psr = | 1410 Trace::DeferredSetRegister* psr = |
| 1366 static_cast<GenerationVariant::DeferredSetRegister*>(action); | 1411 static_cast<Trace::DeferredSetRegister*>(action); |
| 1367 value += psr->value(); | 1412 value += psr->value(); |
| 1368 absolute = true; | 1413 absolute = true; |
| 1369 ASSERT_EQ(store_position, -1); | 1414 ASSERT_EQ(store_position, -1); |
| 1415 ASSERT(!clear); |
| 1370 break; | 1416 break; |
| 1371 } | 1417 } |
| 1372 case ActionNode::INCREMENT_REGISTER: | 1418 case ActionNode::INCREMENT_REGISTER: |
| 1373 if (!absolute) { | 1419 if (!absolute) { |
| 1374 value++; | 1420 value++; |
| 1375 } | 1421 } |
| 1376 ASSERT_EQ(store_position, -1); | 1422 ASSERT_EQ(store_position, -1); |
| 1423 ASSERT(!clear); |
| 1377 break; | 1424 break; |
| 1378 case ActionNode::STORE_POSITION: { | 1425 case ActionNode::STORE_POSITION: { |
| 1379 GenerationVariant::DeferredCapture* pc = | 1426 Trace::DeferredCapture* pc = |
| 1380 static_cast<GenerationVariant::DeferredCapture*>(action); | 1427 static_cast<Trace::DeferredCapture*>(action); |
| 1381 if (store_position == -1) { | 1428 if (!clear && store_position == -1) { |
| 1382 store_position = pc->cp_offset(); | 1429 store_position = pc->cp_offset(); |
| 1383 } | 1430 } |
| 1384 ASSERT(!absolute); | 1431 ASSERT(!absolute); |
| 1385 ASSERT_EQ(value, 0); | 1432 ASSERT_EQ(value, 0); |
| 1386 break; | 1433 break; |
| 1387 } | 1434 } |
| 1435 case ActionNode::CLEAR_CAPTURES: { |
| 1436 // Since we're scanning in reverse order, if we've already |
| 1437 // set the position we have to ignore historically earlier |
| 1438 // clearing operations. |
| 1439 if (store_position == -1) |
| 1440 clear = true; |
| 1441 ASSERT(!absolute); |
| 1442 ASSERT_EQ(value, 0); |
| 1443 break; |
| 1444 } |
| 1388 default: | 1445 default: |
| 1389 UNREACHABLE(); | 1446 UNREACHABLE(); |
| 1390 break; | 1447 break; |
| 1391 } | 1448 } |
| 1392 } | 1449 } |
| 1393 } | 1450 } |
| 1394 if (store_position != -1) { | 1451 if (store_position != -1) { |
| 1395 assembler->WriteCurrentPositionToRegister(reg, store_position); | 1452 assembler->WriteCurrentPositionToRegister(reg, store_position); |
| 1396 } else { | 1453 } else if (clear) { |
| 1397 if (absolute) { | 1454 assembler->ClearRegister(reg); |
| 1398 assembler->SetRegister(reg, value); | 1455 } else if (absolute) { |
| 1399 } else { | 1456 assembler->SetRegister(reg, value); |
| 1400 if (value != 0) { | 1457 } else if (value != 0) { |
| 1401 assembler->AdvanceRegister(reg, value); | 1458 assembler->AdvanceRegister(reg, value); |
| 1402 } | |
| 1403 } | |
| 1404 } | 1459 } |
| 1405 } | 1460 } |
| 1406 } | 1461 } |
| 1407 | 1462 |
| 1408 | 1463 |
| 1409 // This is called as we come into a loop choice node and some other tricky | 1464 // This is called as we come into a loop choice node and some other tricky |
| 1410 // nodes. It normalises the state of the code generator to ensure we can | 1465 // nodes. It normalises the state of the code generator to ensure we can |
| 1411 // generate generic code. | 1466 // generate generic code. |
| 1412 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) { | 1467 bool Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
| 1413 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1468 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1414 | 1469 |
| 1415 ASSERT(actions_ != NULL || | 1470 ASSERT(actions_ != NULL || |
| 1416 cp_offset_ != 0 || | 1471 cp_offset_ != 0 || |
| 1417 backtrack() != NULL || | 1472 backtrack() != NULL || |
| 1418 characters_preloaded_ != 0 || | 1473 characters_preloaded_ != 0 || |
| 1419 quick_check_performed_.characters() != 0 || | 1474 quick_check_performed_.characters() != 0 || |
| 1420 bound_checked_up_to_ != 0); | 1475 bound_checked_up_to_ != 0); |
| 1421 | 1476 |
| 1422 if (actions_ == NULL && backtrack() == NULL) { | 1477 if (actions_ == NULL && backtrack() == NULL) { |
| 1423 // Here we just have some deferred cp advances to fix and we are back to | 1478 // Here we just have some deferred cp advances to fix and we are back to |
| 1424 // a normal situation. We may also have to forget some information gained | 1479 // a normal situation. We may also have to forget some information gained |
| 1425 // through a quick check that was already performed. | 1480 // through a quick check that was already performed. |
| 1426 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); | 1481 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); |
| 1427 // Create a new trivial state and generate the node with that. | 1482 // Create a new trivial state and generate the node with that. |
| 1428 GenerationVariant new_state; | 1483 Trace new_state; |
| 1429 return successor->Emit(compiler, &new_state); | 1484 return successor->Emit(compiler, &new_state); |
| 1430 } | 1485 } |
| 1431 | 1486 |
| 1432 // Generate deferred actions here along with code to undo them again. | 1487 // Generate deferred actions here along with code to undo them again. |
| 1433 OutSet affected_registers; | 1488 OutSet affected_registers; |
| 1434 int max_register = FindAffectedRegisters(&affected_registers); | 1489 int max_register = FindAffectedRegisters(&affected_registers); |
| 1435 PushAffectedRegisters(assembler, max_register, affected_registers); | 1490 PushAffectedRegisters(assembler, max_register, affected_registers); |
| 1436 PerformDeferredActions(assembler, max_register, affected_registers); | 1491 PerformDeferredActions(assembler, max_register, affected_registers); |
| 1437 if (backtrack() != NULL) { | 1492 if (backtrack() != NULL) { |
| 1438 // Here we have a concrete backtrack location. These are set up by choice | 1493 // Here we have a concrete backtrack location. These are set up by choice |
| 1439 // nodes and so they indicate that we have a deferred save of the current | 1494 // nodes and so they indicate that we have a deferred save of the current |
| 1440 // position which we may need to emit here. | 1495 // position which we may need to emit here. |
| 1441 assembler->PushCurrentPosition(); | 1496 assembler->PushCurrentPosition(); |
| 1442 } | 1497 } |
| 1443 if (cp_offset_ != 0) { | 1498 if (cp_offset_ != 0) { |
| 1444 assembler->AdvanceCurrentPosition(cp_offset_); | 1499 assembler->AdvanceCurrentPosition(cp_offset_); |
| 1445 } | 1500 } |
| 1446 | 1501 |
| 1447 // Create a new trivial state and generate the node with that. | 1502 // Create a new trivial state and generate the node with that. |
| 1448 Label undo; | 1503 Label undo; |
| 1449 assembler->PushBacktrack(&undo); | 1504 assembler->PushBacktrack(&undo); |
| 1450 GenerationVariant new_state; | 1505 Trace new_state; |
| 1451 bool ok = successor->Emit(compiler, &new_state); | 1506 bool ok = successor->Emit(compiler, &new_state); |
| 1452 | 1507 |
| 1453 // On backtrack we need to restore state. | 1508 // On backtrack we need to restore state. |
| 1454 assembler->Bind(&undo); | 1509 assembler->Bind(&undo); |
| 1455 if (!ok) return false; | 1510 if (!ok) return false; |
| 1456 if (backtrack() != NULL) { | 1511 if (backtrack() != NULL) { |
| 1457 assembler->PopCurrentPosition(); | 1512 assembler->PopCurrentPosition(); |
| 1458 } | 1513 } |
| 1459 RestoreAffectedRegisters(assembler, max_register, affected_registers); | 1514 RestoreAffectedRegisters(assembler, max_register, affected_registers); |
| 1460 if (backtrack() == NULL) { | 1515 if (backtrack() == NULL) { |
| 1461 assembler->Backtrack(); | 1516 assembler->Backtrack(); |
| 1462 } else { | 1517 } else { |
| 1463 assembler->GoTo(backtrack()); | 1518 assembler->GoTo(backtrack()); |
| 1464 } | 1519 } |
| 1465 | 1520 |
| 1466 return true; | 1521 return true; |
| 1467 } | 1522 } |
| 1468 | 1523 |
| 1469 | 1524 |
| 1470 void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, | 1525 void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, Trace* trace) { |
| 1471 GenerationVariant* variant) { | |
| 1472 if (info()->at_end) { | 1526 if (info()->at_end) { |
| 1473 Label succeed; | 1527 Label succeed; |
| 1474 // LoadCurrentCharacter will go to the label if we are at the end of the | 1528 // LoadCurrentCharacter will go to the label if we are at the end of the |
| 1475 // input string. | 1529 // input string. |
| 1476 assembler->LoadCurrentCharacter(0, &succeed); | 1530 assembler->LoadCurrentCharacter(0, &succeed); |
| 1477 assembler->GoTo(variant->backtrack()); | 1531 assembler->GoTo(trace->backtrack()); |
| 1478 assembler->Bind(&succeed); | 1532 assembler->Bind(&succeed); |
| 1479 } | 1533 } |
| 1480 } | 1534 } |
| 1481 | 1535 |
| 1482 | 1536 |
| 1483 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, | 1537 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 1484 GenerationVariant* variant) { | 1538 if (!trace->is_trivial()) { |
| 1485 if (!variant->is_trivial()) { | 1539 return trace->Flush(compiler, this); |
| 1486 return variant->Flush(compiler, this); | |
| 1487 } | 1540 } |
| 1488 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1541 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1489 if (!label()->is_bound()) { | 1542 if (!label()->is_bound()) { |
| 1490 assembler->Bind(label()); | 1543 assembler->Bind(label()); |
| 1491 } | 1544 } |
| 1492 EmitInfoChecks(assembler, variant); | 1545 EmitInfoChecks(assembler, trace); |
| 1493 assembler->ReadCurrentPositionFromRegister(current_position_register_); | 1546 assembler->ReadCurrentPositionFromRegister(current_position_register_); |
| 1494 assembler->ReadStackPointerFromRegister(stack_pointer_register_); | 1547 assembler->ReadStackPointerFromRegister(stack_pointer_register_); |
| 1495 // Now that we have unwound the stack we find at the top of the stack the | 1548 // Now that we have unwound the stack we find at the top of the stack the |
| 1496 // backtrack that the BeginSubmatch node got. | 1549 // backtrack that the BeginSubmatch node got. |
| 1497 assembler->Backtrack(); | 1550 assembler->Backtrack(); |
| 1498 return true; | 1551 return true; |
| 1499 } | 1552 } |
| 1500 | 1553 |
| 1501 | 1554 |
| 1502 bool EndNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 1555 bool EndNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 1503 if (!variant->is_trivial()) { | 1556 if (!trace->is_trivial()) { |
| 1504 return variant->Flush(compiler, this); | 1557 return trace->Flush(compiler, this); |
| 1505 } | 1558 } |
| 1506 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1559 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1507 if (!label()->is_bound()) { | 1560 if (!label()->is_bound()) { |
| 1508 assembler->Bind(label()); | 1561 assembler->Bind(label()); |
| 1509 } | 1562 } |
| 1510 switch (action_) { | 1563 switch (action_) { |
| 1511 case ACCEPT: | 1564 case ACCEPT: |
| 1512 EmitInfoChecks(assembler, variant); | 1565 EmitInfoChecks(assembler, trace); |
| 1513 assembler->Succeed(); | 1566 assembler->Succeed(); |
| 1514 return true; | 1567 return true; |
| 1515 case BACKTRACK: | 1568 case BACKTRACK: |
| 1516 ASSERT(!info()->at_end); | 1569 ASSERT(!info()->at_end); |
| 1517 assembler->GoTo(variant->backtrack()); | 1570 assembler->GoTo(trace->backtrack()); |
| 1518 return true; | 1571 return true; |
| 1519 case NEGATIVE_SUBMATCH_SUCCESS: | 1572 case NEGATIVE_SUBMATCH_SUCCESS: |
| 1520 // This case is handled in a different virtual method. | 1573 // This case is handled in a different virtual method. |
| 1521 UNREACHABLE(); | 1574 UNREACHABLE(); |
| 1522 } | 1575 } |
| 1523 UNIMPLEMENTED(); | 1576 UNIMPLEMENTED(); |
| 1524 return false; | 1577 return false; |
| 1525 } | 1578 } |
| 1526 | 1579 |
| 1527 | 1580 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1549 } | 1602 } |
| 1550 | 1603 |
| 1551 | 1604 |
| 1552 ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) { | 1605 ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) { |
| 1553 ActionNode* result = new ActionNode(STORE_POSITION, on_success); | 1606 ActionNode* result = new ActionNode(STORE_POSITION, on_success); |
| 1554 result->data_.u_position_register.reg = reg; | 1607 result->data_.u_position_register.reg = reg; |
| 1555 return result; | 1608 return result; |
| 1556 } | 1609 } |
| 1557 | 1610 |
| 1558 | 1611 |
| 1612 ActionNode* ActionNode::ClearCaptures(Interval range, |
| 1613 RegExpNode* on_success) { |
| 1614 ActionNode* result = new ActionNode(CLEAR_CAPTURES, on_success); |
| 1615 result->data_.u_clear_captures.range_from = range.from(); |
| 1616 result->data_.u_clear_captures.range_to = range.to(); |
| 1617 return result; |
| 1618 } |
| 1619 |
| 1620 |
| 1559 ActionNode* ActionNode::BeginSubmatch(int stack_reg, | 1621 ActionNode* ActionNode::BeginSubmatch(int stack_reg, |
| 1560 int position_reg, | 1622 int position_reg, |
| 1561 RegExpNode* on_success) { | 1623 RegExpNode* on_success) { |
| 1562 ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success); | 1624 ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success); |
| 1563 result->data_.u_submatch.stack_pointer_register = stack_reg; | 1625 result->data_.u_submatch.stack_pointer_register = stack_reg; |
| 1564 result->data_.u_submatch.current_position_register = position_reg; | 1626 result->data_.u_submatch.current_position_register = position_reg; |
| 1565 return result; | 1627 return result; |
| 1566 } | 1628 } |
| 1567 | 1629 |
| 1568 | 1630 |
| 1569 ActionNode* ActionNode::PositiveSubmatchSuccess(int stack_reg, | 1631 ActionNode* ActionNode::PositiveSubmatchSuccess(int stack_reg, |
| 1570 int position_reg, | 1632 int position_reg, |
| 1571 RegExpNode* on_success) { | 1633 RegExpNode* on_success) { |
| 1572 ActionNode* result = new ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success); | 1634 ActionNode* result = new ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success); |
| 1573 result->data_.u_submatch.stack_pointer_register = stack_reg; | 1635 result->data_.u_submatch.stack_pointer_register = stack_reg; |
| 1574 result->data_.u_submatch.current_position_register = position_reg; | 1636 result->data_.u_submatch.current_position_register = position_reg; |
| 1575 return result; | 1637 return result; |
| 1576 } | 1638 } |
| 1577 | 1639 |
| 1578 | 1640 |
| 1641 ActionNode* ActionNode::EmptyMatchCheck(int start_register, |
| 1642 int repetition_register, |
| 1643 int repetition_limit, |
| 1644 RegExpNode* on_success) { |
| 1645 ActionNode* result = new ActionNode(EMPTY_MATCH_CHECK, on_success); |
| 1646 result->data_.u_empty_match_check.start_register = start_register; |
| 1647 result->data_.u_empty_match_check.repetition_register = repetition_register; |
| 1648 result->data_.u_empty_match_check.repetition_limit = repetition_limit; |
| 1649 return result; |
| 1650 } |
| 1651 |
| 1652 |
| 1579 #define DEFINE_ACCEPT(Type) \ | 1653 #define DEFINE_ACCEPT(Type) \ |
| 1580 void Type##Node::Accept(NodeVisitor* visitor) { \ | 1654 void Type##Node::Accept(NodeVisitor* visitor) { \ |
| 1581 visitor->Visit##Type(this); \ | 1655 visitor->Visit##Type(this); \ |
| 1582 } | 1656 } |
| 1583 FOR_EACH_NODE_TYPE(DEFINE_ACCEPT) | 1657 FOR_EACH_NODE_TYPE(DEFINE_ACCEPT) |
| 1584 #undef DEFINE_ACCEPT | 1658 #undef DEFINE_ACCEPT |
| 1585 | 1659 |
| 1586 | 1660 |
| 1587 void LoopChoiceNode::Accept(NodeVisitor* visitor) { | 1661 void LoopChoiceNode::Accept(NodeVisitor* visitor) { |
| 1588 visitor->VisitLoopChoice(this); | 1662 visitor->VisitLoopChoice(this); |
| 1589 } | 1663 } |
| 1590 | 1664 |
| 1591 | 1665 |
| 1592 // ------------------------------------------------------------------- | 1666 // ------------------------------------------------------------------- |
| 1593 // Emit code. | 1667 // Emit code. |
| 1594 | 1668 |
| 1595 | 1669 |
| 1596 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, | 1670 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 1597 Guard* guard, | 1671 Guard* guard, |
| 1598 GenerationVariant* variant) { | 1672 Trace* trace) { |
| 1599 switch (guard->op()) { | 1673 switch (guard->op()) { |
| 1600 case Guard::LT: | 1674 case Guard::LT: |
| 1601 ASSERT(!variant->mentions_reg(guard->reg())); | 1675 ASSERT(!trace->mentions_reg(guard->reg())); |
| 1602 macro_assembler->IfRegisterGE(guard->reg(), | 1676 macro_assembler->IfRegisterGE(guard->reg(), |
| 1603 guard->value(), | 1677 guard->value(), |
| 1604 variant->backtrack()); | 1678 trace->backtrack()); |
| 1605 break; | 1679 break; |
| 1606 case Guard::GEQ: | 1680 case Guard::GEQ: |
| 1607 ASSERT(!variant->mentions_reg(guard->reg())); | 1681 ASSERT(!trace->mentions_reg(guard->reg())); |
| 1608 macro_assembler->IfRegisterLT(guard->reg(), | 1682 macro_assembler->IfRegisterLT(guard->reg(), |
| 1609 guard->value(), | 1683 guard->value(), |
| 1610 variant->backtrack()); | 1684 trace->backtrack()); |
| 1611 break; | 1685 break; |
| 1612 } | 1686 } |
| 1613 } | 1687 } |
| 1614 | 1688 |
| 1615 | 1689 |
| 1616 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; | 1690 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; |
| 1617 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; | 1691 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; |
| 1618 | 1692 |
| 1619 | 1693 |
| 1620 // Only emits non-letters (things that don't have case). Only used for case | 1694 // Only emits non-letters (things that don't have case). Only used for case |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1853 } | 1927 } |
| 1854 macro_assembler->Bind(&success); | 1928 macro_assembler->Bind(&success); |
| 1855 } | 1929 } |
| 1856 | 1930 |
| 1857 | 1931 |
| 1858 RegExpNode::~RegExpNode() { | 1932 RegExpNode::~RegExpNode() { |
| 1859 } | 1933 } |
| 1860 | 1934 |
| 1861 | 1935 |
| 1862 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, | 1936 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, |
| 1863 GenerationVariant* variant) { | 1937 Trace* trace) { |
| 1864 // TODO(erikcorry): Implement support. | 1938 // TODO(erikcorry): Implement support. |
| 1865 if (info_.follows_word_interest || | 1939 if (info_.follows_word_interest || |
| 1866 info_.follows_newline_interest || | 1940 info_.follows_newline_interest || |
| 1867 info_.follows_start_interest) { | 1941 info_.follows_start_interest) { |
| 1868 return FAIL; | 1942 return FAIL; |
| 1869 } | 1943 } |
| 1870 | 1944 |
| 1871 // If we are generating a greedy loop then don't stop and don't reuse code. | 1945 // If we are generating a greedy loop then don't stop and don't reuse code. |
| 1872 if (variant->stop_node() != NULL) { | 1946 if (trace->stop_node() != NULL) { |
| 1873 return CONTINUE; | 1947 return CONTINUE; |
| 1874 } | 1948 } |
| 1875 | 1949 |
| 1876 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 1950 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 1877 if (variant->is_trivial()) { | 1951 if (trace->is_trivial()) { |
| 1878 if (label_.is_bound()) { | 1952 if (label_.is_bound()) { |
| 1879 // We are being asked to generate a generic version, but that's already | 1953 // We are being asked to generate a generic version, but that's already |
| 1880 // been done so just go to it. | 1954 // been done so just go to it. |
| 1881 macro_assembler->GoTo(&label_); | 1955 macro_assembler->GoTo(&label_); |
| 1882 return DONE; | 1956 return DONE; |
| 1883 } | 1957 } |
| 1884 if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) { | 1958 if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) { |
| 1885 // To avoid too deep recursion we push the node to the work queue and just | 1959 // To avoid too deep recursion we push the node to the work queue and just |
| 1886 // generate a goto here. | 1960 // generate a goto here. |
| 1887 compiler->AddWork(this); | 1961 compiler->AddWork(this); |
| 1888 macro_assembler->GoTo(&label_); | 1962 macro_assembler->GoTo(&label_); |
| 1889 return DONE; | 1963 return DONE; |
| 1890 } | 1964 } |
| 1891 // Generate generic version of the node and bind the label for later use. | 1965 // Generate generic version of the node and bind the label for later use. |
| 1892 macro_assembler->Bind(&label_); | 1966 macro_assembler->Bind(&label_); |
| 1893 return CONTINUE; | 1967 return CONTINUE; |
| 1894 } | 1968 } |
| 1895 | 1969 |
| 1896 // We are being asked to make a non-generic version. Keep track of how many | 1970 // We are being asked to make a non-generic version. Keep track of how many |
| 1897 // non-generic versions we generate so as not to overdo it. | 1971 // non-generic versions we generate so as not to overdo it. |
| 1898 variants_generated_++; | 1972 trace_count_++; |
| 1899 if (variants_generated_ < kMaxVariantsGenerated && | 1973 if (trace_count_ < kMaxCopiesCodeGenerated && |
| 1900 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { | 1974 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
| 1901 return CONTINUE; | 1975 return CONTINUE; |
| 1902 } | 1976 } |
| 1903 | 1977 |
| 1904 // If we get here there have been too many variants generated or recursion | 1978 // If we get here code has been generated for this node too many times or |
| 1905 // is too deep. Time to switch to a generic version. The code for | 1979 // recursion is too deep. Time to switch to a generic version. The code for |
| 1906 // generic versions above can handle deep recursion properly. | 1980 // generic versions above can handle deep recursion properly. |
| 1907 bool ok = variant->Flush(compiler, this); | 1981 bool ok = trace->Flush(compiler, this); |
| 1908 return ok ? DONE : FAIL; | 1982 return ok ? DONE : FAIL; |
| 1909 } | 1983 } |
| 1910 | 1984 |
| 1911 | 1985 |
| 1912 int ActionNode::EatsAtLeast(int recursion_depth) { | 1986 int ActionNode::EatsAtLeast(int recursion_depth) { |
| 1913 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; | 1987 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; |
| 1914 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! | 1988 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! |
| 1915 return on_success()->EatsAtLeast(recursion_depth + 1); | 1989 return on_success()->EatsAtLeast(recursion_depth + 1); |
| 1916 } | 1990 } |
| 1917 | 1991 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1978 } | 2052 } |
| 1979 mask_ |= (pos->mask & char_mask) << char_shift; | 2053 mask_ |= (pos->mask & char_mask) << char_shift; |
| 1980 value_ |= (pos->value & char_mask) << char_shift; | 2054 value_ |= (pos->value & char_mask) << char_shift; |
| 1981 char_shift += asc ? 8 : 16; | 2055 char_shift += asc ? 8 : 16; |
| 1982 } | 2056 } |
| 1983 return found_useful_op; | 2057 return found_useful_op; |
| 1984 } | 2058 } |
| 1985 | 2059 |
| 1986 | 2060 |
| 1987 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, | 2061 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, |
| 1988 GenerationVariant* variant, | 2062 Trace* trace, |
| 1989 bool preload_has_checked_bounds, | 2063 bool preload_has_checked_bounds, |
| 1990 Label* on_possible_success, | 2064 Label* on_possible_success, |
| 1991 QuickCheckDetails* details, | 2065 QuickCheckDetails* details, |
| 1992 bool fall_through_on_failure) { | 2066 bool fall_through_on_failure) { |
| 1993 if (details->characters() == 0) return false; | 2067 if (details->characters() == 0) return false; |
| 1994 GetQuickCheckDetails(details, compiler, 0); | 2068 GetQuickCheckDetails(details, compiler, 0); |
| 1995 if (!details->Rationalize(compiler->ascii())) return false; | 2069 if (!details->Rationalize(compiler->ascii())) return false; |
| 1996 uint32_t mask = details->mask(); | 2070 uint32_t mask = details->mask(); |
| 1997 uint32_t value = details->value(); | 2071 uint32_t value = details->value(); |
| 1998 | 2072 |
| 1999 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2073 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2000 | 2074 |
| 2001 if (variant->characters_preloaded() != details->characters()) { | 2075 if (trace->characters_preloaded() != details->characters()) { |
| 2002 assembler->LoadCurrentCharacter(variant->cp_offset(), | 2076 assembler->LoadCurrentCharacter(trace->cp_offset(), |
| 2003 variant->backtrack(), | 2077 trace->backtrack(), |
| 2004 !preload_has_checked_bounds, | 2078 !preload_has_checked_bounds, |
| 2005 details->characters()); | 2079 details->characters()); |
| 2006 } | 2080 } |
| 2007 | 2081 |
| 2008 | 2082 |
| 2009 bool need_mask = true; | 2083 bool need_mask = true; |
| 2010 | 2084 |
| 2011 if (details->characters() == 1) { | 2085 if (details->characters() == 1) { |
| 2012 // If number of characters preloaded is 1 then we used a byte or 16 bit | 2086 // If number of characters preloaded is 1 then we used a byte or 16 bit |
| 2013 // load so the value is already masked down. | 2087 // load so the value is already masked down. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2030 } | 2104 } |
| 2031 | 2105 |
| 2032 if (fall_through_on_failure) { | 2106 if (fall_through_on_failure) { |
| 2033 if (need_mask) { | 2107 if (need_mask) { |
| 2034 assembler->CheckCharacterAfterAnd(value, mask, on_possible_success); | 2108 assembler->CheckCharacterAfterAnd(value, mask, on_possible_success); |
| 2035 } else { | 2109 } else { |
| 2036 assembler->CheckCharacter(value, on_possible_success); | 2110 assembler->CheckCharacter(value, on_possible_success); |
| 2037 } | 2111 } |
| 2038 } else { | 2112 } else { |
| 2039 if (need_mask) { | 2113 if (need_mask) { |
| 2040 assembler->CheckNotCharacterAfterAnd(value, mask, variant->backtrack()); | 2114 assembler->CheckNotCharacterAfterAnd(value, mask, trace->backtrack()); |
| 2041 } else { | 2115 } else { |
| 2042 assembler->CheckNotCharacter(value, variant->backtrack()); | 2116 assembler->CheckNotCharacter(value, trace->backtrack()); |
| 2043 } | 2117 } |
| 2044 } | 2118 } |
| 2045 return true; | 2119 return true; |
| 2046 } | 2120 } |
| 2047 | 2121 |
| 2048 | 2122 |
| 2049 // Here is the meat of GetQuickCheckDetails (see also the comment on the | 2123 // Here is the meat of GetQuickCheckDetails (see also the comment on the |
| 2050 // super-class in the .h file). | 2124 // super-class in the .h file). |
| 2051 // | 2125 // |
| 2052 // We iterate along the text object, building up for each character a | 2126 // We iterate along the text object, building up for each character a |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2218 pos->mask &= other_pos->mask; | 2292 pos->mask &= other_pos->mask; |
| 2219 pos->value &= pos->mask; | 2293 pos->value &= pos->mask; |
| 2220 other_pos->value &= pos->mask; | 2294 other_pos->value &= pos->mask; |
| 2221 uc16 differing_bits = (pos->value ^ other_pos->value); | 2295 uc16 differing_bits = (pos->value ^ other_pos->value); |
| 2222 pos->mask &= ~differing_bits; | 2296 pos->mask &= ~differing_bits; |
| 2223 pos->value &= pos->mask; | 2297 pos->value &= pos->mask; |
| 2224 } | 2298 } |
| 2225 } | 2299 } |
| 2226 | 2300 |
| 2227 | 2301 |
| 2302 class VisitMarker { |
| 2303 public: |
| 2304 explicit VisitMarker(NodeInfo* info) : info_(info) { |
| 2305 ASSERT(!info->visited); |
| 2306 info->visited = true; |
| 2307 } |
| 2308 ~VisitMarker() { |
| 2309 info_->visited = false; |
| 2310 } |
| 2311 private: |
| 2312 NodeInfo* info_; |
| 2313 }; |
| 2314 |
| 2315 |
| 2228 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, | 2316 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2229 RegExpCompiler* compiler, | 2317 RegExpCompiler* compiler, |
| 2230 int characters_filled_in) { | 2318 int characters_filled_in) { |
| 2231 if (body_can_be_zero_length_) return; | 2319 if (body_can_be_zero_length_ || info()->visited) return; |
| 2320 VisitMarker marker(info()); |
| 2232 return ChoiceNode::GetQuickCheckDetails(details, | 2321 return ChoiceNode::GetQuickCheckDetails(details, |
| 2233 compiler, | 2322 compiler, |
| 2234 characters_filled_in); | 2323 characters_filled_in); |
| 2235 } | 2324 } |
| 2236 | 2325 |
| 2237 | 2326 |
| 2238 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, | 2327 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2239 RegExpCompiler* compiler, | 2328 RegExpCompiler* compiler, |
| 2240 int characters_filled_in) { | 2329 int characters_filled_in) { |
| 2241 int choice_count = alternatives_->length(); | 2330 int choice_count = alternatives_->length(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2267 // end-of-input when loading the putative 'r'. | 2356 // end-of-input when loading the putative 'r'. |
| 2268 // | 2357 // |
| 2269 // A slight complication involves the fact that the first character may already | 2358 // A slight complication involves the fact that the first character may already |
| 2270 // be fetched into a register by the previous node. In this case we want to | 2359 // be fetched into a register by the previous node. In this case we want to |
| 2271 // do the test for that character first. We do this in separate passes. The | 2360 // do the test for that character first. We do this in separate passes. The |
| 2272 // 'preloaded' argument indicates that we are doing such a 'pass'. If such a | 2361 // 'preloaded' argument indicates that we are doing such a 'pass'. If such a |
| 2273 // pass has been performed then subsequent passes will have true in | 2362 // pass has been performed then subsequent passes will have true in |
| 2274 // first_element_checked to indicate that that character does not need to be | 2363 // first_element_checked to indicate that that character does not need to be |
| 2275 // checked again. | 2364 // checked again. |
| 2276 // | 2365 // |
| 2277 // In addition to all this we are passed a GenerationVariant, which can | 2366 // In addition to all this we are passed a Trace, which can |
| 2278 // contain an AlternativeGeneration object. In this AlternativeGeneration | 2367 // contain an AlternativeGeneration object. In this AlternativeGeneration |
| 2279 // object we can see details of any quick check that was already passed in | 2368 // object we can see details of any quick check that was already passed in |
| 2280 // order to get to the code we are now generating. The quick check can involve | 2369 // order to get to the code we are now generating. The quick check can involve |
| 2281 // loading characters, which means we do not need to recheck the bounds | 2370 // loading characters, which means we do not need to recheck the bounds |
| 2282 // up to the limit the quick check already checked. In addition the quick | 2371 // up to the limit the quick check already checked. In addition the quick |
| 2283 // check can have involved a mask and compare operation which may simplify | 2372 // check can have involved a mask and compare operation which may simplify |
| 2284 // or obviate the need for further checks at some character positions. | 2373 // or obviate the need for further checks at some character positions. |
| 2285 void TextNode::TextEmitPass(RegExpCompiler* compiler, | 2374 void TextNode::TextEmitPass(RegExpCompiler* compiler, |
| 2286 TextEmitPassType pass, | 2375 TextEmitPassType pass, |
| 2287 bool preloaded, | 2376 bool preloaded, |
| 2288 GenerationVariant* variant, | 2377 Trace* trace, |
| 2289 bool first_element_checked, | 2378 bool first_element_checked, |
| 2290 int* checked_up_to) { | 2379 int* checked_up_to) { |
| 2291 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2380 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2292 bool ascii = compiler->ascii(); | 2381 bool ascii = compiler->ascii(); |
| 2293 Label* backtrack = variant->backtrack(); | 2382 Label* backtrack = trace->backtrack(); |
| 2294 QuickCheckDetails* quick_check = variant->quick_check_performed(); | 2383 QuickCheckDetails* quick_check = trace->quick_check_performed(); |
| 2295 int element_count = elms_->length(); | 2384 int element_count = elms_->length(); |
| 2296 for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) { | 2385 for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) { |
| 2297 TextElement elm = elms_->at(i); | 2386 TextElement elm = elms_->at(i); |
| 2298 int cp_offset = variant->cp_offset() + elm.cp_offset; | 2387 int cp_offset = trace->cp_offset() + elm.cp_offset; |
| 2299 if (elm.type == TextElement::ATOM) { | 2388 if (elm.type == TextElement::ATOM) { |
| 2300 if (pass == NON_ASCII_MATCH || | 2389 if (pass == NON_ASCII_MATCH || |
| 2301 pass == CHARACTER_MATCH || | 2390 pass == CHARACTER_MATCH || |
| 2302 pass == CASE_CHARACTER_MATCH) { | 2391 pass == CASE_CHARACTER_MATCH) { |
| 2303 Vector<const uc16> quarks = elm.data.u_atom->data(); | 2392 Vector<const uc16> quarks = elm.data.u_atom->data(); |
| 2304 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { | 2393 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { |
| 2305 bool bound_checked = true; // Most ops will check their bounds. | 2394 bool bound_checked = true; // Most ops will check their bounds. |
| 2306 if (first_element_checked && i == 0 && j == 0) continue; | 2395 if (first_element_checked && i == 0 && j == 0) continue; |
| 2307 if (quick_check != NULL && | 2396 if (quick_check != NULL && |
| 2308 elm.cp_offset + j < quick_check->characters() && | 2397 elm.cp_offset + j < quick_check->characters() && |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2385 } | 2474 } |
| 2386 } | 2475 } |
| 2387 | 2476 |
| 2388 | 2477 |
| 2389 // This generates the code to match a text node. A text node can contain | 2478 // This generates the code to match a text node. A text node can contain |
| 2390 // straight character sequences (possibly to be matched in a case-independent | 2479 // straight character sequences (possibly to be matched in a case-independent |
| 2391 // way) and character classes. For efficiency we do not do this in a single | 2480 // way) and character classes. For efficiency we do not do this in a single |
| 2392 // pass from left to right. Instead we pass over the text node several times, | 2481 // pass from left to right. Instead we pass over the text node several times, |
| 2393 // emitting code for some character positions every time. See the comment on | 2482 // emitting code for some character positions every time. See the comment on |
| 2394 // TextEmitPass for details. | 2483 // TextEmitPass for details. |
| 2395 bool TextNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2484 bool TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2396 LimitResult limit_result = LimitVersions(compiler, variant); | 2485 LimitResult limit_result = LimitVersions(compiler, trace); |
| 2397 if (limit_result == FAIL) return false; | 2486 if (limit_result == FAIL) return false; |
| 2398 if (limit_result == DONE) return true; | 2487 if (limit_result == DONE) return true; |
| 2399 ASSERT(limit_result == CONTINUE); | 2488 ASSERT(limit_result == CONTINUE); |
| 2400 | 2489 |
| 2401 if (info()->follows_word_interest || | 2490 if (info()->follows_word_interest || |
| 2402 info()->follows_newline_interest || | 2491 info()->follows_newline_interest || |
| 2403 info()->follows_start_interest) { | 2492 info()->follows_start_interest) { |
| 2404 return false; | 2493 return false; |
| 2405 } | 2494 } |
| 2406 | 2495 |
| 2407 if (info()->at_end) { | 2496 if (info()->at_end) { |
| 2408 compiler->macro_assembler()->GoTo(variant->backtrack()); | 2497 compiler->macro_assembler()->GoTo(trace->backtrack()); |
| 2409 return true; | 2498 return true; |
| 2410 } | 2499 } |
| 2411 | 2500 |
| 2412 if (compiler->ascii()) { | 2501 if (compiler->ascii()) { |
| 2413 int dummy = 0; | 2502 int dummy = 0; |
| 2414 TextEmitPass(compiler, NON_ASCII_MATCH, false, variant, false, &dummy); | 2503 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); |
| 2415 } | 2504 } |
| 2416 | 2505 |
| 2417 bool first_elt_done = false; | 2506 bool first_elt_done = false; |
| 2418 int bound_checked_to = variant->cp_offset() - 1; | 2507 int bound_checked_to = trace->cp_offset() - 1; |
| 2419 bound_checked_to += variant->bound_checked_up_to(); | 2508 bound_checked_to += trace->bound_checked_up_to(); |
| 2420 | 2509 |
| 2421 // If a character is preloaded into the current character register then | 2510 // If a character is preloaded into the current character register then |
| 2422 // check that now. | 2511 // check that now. |
| 2423 if (variant->characters_preloaded() == 1) { | 2512 if (trace->characters_preloaded() == 1) { |
| 2424 TextEmitPass(compiler, | 2513 TextEmitPass(compiler, |
| 2425 CHARACTER_MATCH, | 2514 CHARACTER_MATCH, |
| 2426 true, | 2515 true, |
| 2427 variant, | 2516 trace, |
| 2428 false, | 2517 false, |
| 2429 &bound_checked_to); | 2518 &bound_checked_to); |
| 2430 if (compiler->ignore_case()) { | 2519 if (compiler->ignore_case()) { |
| 2431 TextEmitPass(compiler, | 2520 TextEmitPass(compiler, |
| 2432 CASE_CHARACTER_MATCH, | 2521 CASE_CHARACTER_MATCH, |
| 2433 true, | 2522 true, |
| 2434 variant, | 2523 trace, |
| 2435 false, | 2524 false, |
| 2436 &bound_checked_to); | 2525 &bound_checked_to); |
| 2437 } | 2526 } |
| 2438 TextEmitPass(compiler, | 2527 TextEmitPass(compiler, |
| 2439 CHARACTER_CLASS_MATCH, | 2528 CHARACTER_CLASS_MATCH, |
| 2440 true, | 2529 true, |
| 2441 variant, | 2530 trace, |
| 2442 false, | 2531 false, |
| 2443 &bound_checked_to); | 2532 &bound_checked_to); |
| 2444 first_elt_done = true; | 2533 first_elt_done = true; |
| 2445 } | 2534 } |
| 2446 | 2535 |
| 2447 TextEmitPass(compiler, | 2536 TextEmitPass(compiler, |
| 2448 CHARACTER_MATCH, | 2537 CHARACTER_MATCH, |
| 2449 false, | 2538 false, |
| 2450 variant, | 2539 trace, |
| 2451 first_elt_done, | 2540 first_elt_done, |
| 2452 &bound_checked_to); | 2541 &bound_checked_to); |
| 2453 if (compiler->ignore_case()) { | 2542 if (compiler->ignore_case()) { |
| 2454 TextEmitPass(compiler, | 2543 TextEmitPass(compiler, |
| 2455 CASE_CHARACTER_MATCH, | 2544 CASE_CHARACTER_MATCH, |
| 2456 false, | 2545 false, |
| 2457 variant, | 2546 trace, |
| 2458 first_elt_done, | 2547 first_elt_done, |
| 2459 &bound_checked_to); | 2548 &bound_checked_to); |
| 2460 } | 2549 } |
| 2461 TextEmitPass(compiler, | 2550 TextEmitPass(compiler, |
| 2462 CHARACTER_CLASS_MATCH, | 2551 CHARACTER_CLASS_MATCH, |
| 2463 false, | 2552 false, |
| 2464 variant, | 2553 trace, |
| 2465 first_elt_done, | 2554 first_elt_done, |
| 2466 &bound_checked_to); | 2555 &bound_checked_to); |
| 2467 | 2556 |
| 2468 GenerationVariant successor_variant(*variant); | 2557 Trace successor_trace(*trace); |
| 2469 successor_variant.AdvanceVariant(Length(), compiler->ascii()); | 2558 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler->ascii()); |
| 2470 RecursionCheck rc(compiler); | 2559 RecursionCheck rc(compiler); |
| 2471 return on_success()->Emit(compiler, &successor_variant); | 2560 return on_success()->Emit(compiler, &successor_trace); |
| 2472 } | 2561 } |
| 2473 | 2562 |
| 2474 | 2563 |
| 2475 void GenerationVariant::AdvanceVariant(int by, bool ascii) { | 2564 void Trace::AdvanceCurrentPositionInTrace(int by, bool ascii) { |
| 2476 ASSERT(by > 0); | 2565 ASSERT(by > 0); |
| 2477 // We don't have an instruction for shifting the current character register | 2566 // We don't have an instruction for shifting the current character register |
| 2478 // down or for using a shifted value for anything so lets just forget that | 2567 // down or for using a shifted value for anything so lets just forget that |
| 2479 // we preloaded any characters into it. | 2568 // we preloaded any characters into it. |
| 2480 characters_preloaded_ = 0; | 2569 characters_preloaded_ = 0; |
| 2481 // Adjust the offsets of the quick check performed information. This | 2570 // Adjust the offsets of the quick check performed information. This |
| 2482 // information is used to find out what we already determined about the | 2571 // information is used to find out what we already determined about the |
| 2483 // characters by means of mask and compare. | 2572 // characters by means of mask and compare. |
| 2484 quick_check_performed_.Advance(by, ascii); | 2573 quick_check_performed_.Advance(by, ascii); |
| 2485 cp_offset_ += by; | 2574 cp_offset_ += by; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2552 } | 2641 } |
| 2553 | 2642 |
| 2554 | 2643 |
| 2555 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { | 2644 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { |
| 2556 ASSERT_EQ(continue_node_, NULL); | 2645 ASSERT_EQ(continue_node_, NULL); |
| 2557 AddAlternative(alt); | 2646 AddAlternative(alt); |
| 2558 continue_node_ = alt.node(); | 2647 continue_node_ = alt.node(); |
| 2559 } | 2648 } |
| 2560 | 2649 |
| 2561 | 2650 |
| 2562 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, | 2651 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2563 GenerationVariant* variant) { | |
| 2564 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2652 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2565 if (variant->stop_node() == this) { | 2653 if (trace->stop_node() == this) { |
| 2566 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2654 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2567 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); | 2655 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); |
| 2568 // Update the counter-based backtracking info on the stack. This is an | 2656 // Update the counter-based backtracking info on the stack. This is an |
| 2569 // optimization for greedy loops (see below). | 2657 // optimization for greedy loops (see below). |
| 2570 ASSERT(variant->cp_offset() == text_length); | 2658 ASSERT(trace->cp_offset() == text_length); |
| 2571 macro_assembler->AdvanceCurrentPosition(text_length); | 2659 macro_assembler->AdvanceCurrentPosition(text_length); |
| 2572 macro_assembler->GoTo(variant->loop_label()); | 2660 macro_assembler->GoTo(trace->loop_label()); |
| 2573 return true; | 2661 return true; |
| 2574 } | 2662 } |
| 2575 ASSERT(variant->stop_node() == NULL); | 2663 ASSERT(trace->stop_node() == NULL); |
| 2576 if (!variant->is_trivial()) { | 2664 if (!trace->is_trivial()) { |
| 2577 return variant->Flush(compiler, this); | 2665 return trace->Flush(compiler, this); |
| 2578 } | 2666 } |
| 2579 return ChoiceNode::Emit(compiler, variant); | 2667 return ChoiceNode::Emit(compiler, trace); |
| 2580 } | 2668 } |
| 2581 | 2669 |
| 2582 | 2670 |
| 2583 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { | 2671 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { |
| 2584 int preload_characters = EatsAtLeast(0); | 2672 int preload_characters = EatsAtLeast(0); |
| 2585 #ifdef CAN_READ_UNALIGNED | 2673 #ifdef CAN_READ_UNALIGNED |
| 2586 bool ascii = compiler->ascii(); | 2674 bool ascii = compiler->ascii(); |
| 2587 if (ascii) { | 2675 if (ascii) { |
| 2588 if (preload_characters > 4) preload_characters = 4; | 2676 if (preload_characters > 4) preload_characters = 4; |
| 2589 // We can't preload 3 characters because there is no machine instruction | 2677 // We can't preload 3 characters because there is no machine instruction |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2722 * | / | | 2810 * | / | |
| 2723 * | R | | 2811 * | R | |
| 2724 * | / | | 2812 * | / | |
| 2725 * F VL | | 2813 * F VL | |
| 2726 * <------U | | 2814 * <------U | |
| 2727 * back |S | | 2815 * back |S | |
| 2728 * \______________/ | 2816 * \______________/ |
| 2729 */ | 2817 */ |
| 2730 | 2818 |
| 2731 | 2819 |
| 2732 bool ChoiceNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2820 bool ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2733 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2821 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2734 int choice_count = alternatives_->length(); | 2822 int choice_count = alternatives_->length(); |
| 2735 #ifdef DEBUG | 2823 #ifdef DEBUG |
| 2736 for (int i = 0; i < choice_count - 1; i++) { | 2824 for (int i = 0; i < choice_count - 1; i++) { |
| 2737 GuardedAlternative alternative = alternatives_->at(i); | 2825 GuardedAlternative alternative = alternatives_->at(i); |
| 2738 ZoneList<Guard*>* guards = alternative.guards(); | 2826 ZoneList<Guard*>* guards = alternative.guards(); |
| 2739 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2827 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2740 for (int j = 0; j < guard_count; j++) { | 2828 for (int j = 0; j < guard_count; j++) { |
| 2741 ASSERT(!variant->mentions_reg(guards->at(j)->reg())); | 2829 ASSERT(!trace->mentions_reg(guards->at(j)->reg())); |
| 2742 } | 2830 } |
| 2743 } | 2831 } |
| 2744 #endif | 2832 #endif |
| 2745 | 2833 |
| 2746 LimitResult limit_result = LimitVersions(compiler, variant); | 2834 LimitResult limit_result = LimitVersions(compiler, trace); |
| 2747 if (limit_result == DONE) return true; | 2835 if (limit_result == DONE) return true; |
| 2748 if (limit_result == FAIL) return false; | 2836 if (limit_result == FAIL) return false; |
| 2749 ASSERT(limit_result == CONTINUE); | 2837 ASSERT(limit_result == CONTINUE); |
| 2750 | 2838 |
| 2751 RecursionCheck rc(compiler); | 2839 RecursionCheck rc(compiler); |
| 2752 | 2840 |
| 2753 GenerationVariant* current_variant = variant; | 2841 Trace* current_trace = trace; |
| 2754 | 2842 |
| 2755 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2843 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2756 bool greedy_loop = false; | 2844 bool greedy_loop = false; |
| 2757 Label greedy_loop_label; | 2845 Label greedy_loop_label; |
| 2758 GenerationVariant counter_backtrack_variant; | 2846 Trace counter_backtrack_trace; |
| 2759 counter_backtrack_variant.set_backtrack(&greedy_loop_label); | 2847 counter_backtrack_trace.set_backtrack(&greedy_loop_label); |
| 2760 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { | 2848 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { |
| 2761 // Here we have special handling for greedy loops containing only text nodes | 2849 // Here we have special handling for greedy loops containing only text nodes |
| 2762 // and other simple nodes. These are handled by pushing the current | 2850 // and other simple nodes. These are handled by pushing the current |
| 2763 // position on the stack and then incrementing the current position each | 2851 // position on the stack and then incrementing the current position each |
| 2764 // time around the switch. On backtrack we decrement the current position | 2852 // time around the switch. On backtrack we decrement the current position |
| 2765 // and check it against the pushed value. This avoids pushing backtrack | 2853 // and check it against the pushed value. This avoids pushing backtrack |
| 2766 // information for each iteration of the loop, which could take up a lot of | 2854 // information for each iteration of the loop, which could take up a lot of |
| 2767 // space. | 2855 // space. |
| 2768 greedy_loop = true; | 2856 greedy_loop = true; |
| 2769 ASSERT(variant->stop_node() == NULL); | 2857 ASSERT(trace->stop_node() == NULL); |
| 2770 macro_assembler->PushCurrentPosition(); | 2858 macro_assembler->PushCurrentPosition(); |
| 2771 current_variant = &counter_backtrack_variant; | 2859 current_trace = &counter_backtrack_trace; |
| 2772 Label greedy_match_failed; | 2860 Label greedy_match_failed; |
| 2773 GenerationVariant greedy_match_variant; | 2861 Trace greedy_match_trace; |
| 2774 greedy_match_variant.set_backtrack(&greedy_match_failed); | 2862 greedy_match_trace.set_backtrack(&greedy_match_failed); |
| 2775 Label loop_label; | 2863 Label loop_label; |
| 2776 macro_assembler->Bind(&loop_label); | 2864 macro_assembler->Bind(&loop_label); |
| 2777 greedy_match_variant.set_stop_node(this); | 2865 greedy_match_trace.set_stop_node(this); |
| 2778 greedy_match_variant.set_loop_label(&loop_label); | 2866 greedy_match_trace.set_loop_label(&loop_label); |
| 2779 bool ok = alternatives_->at(0).node()->Emit(compiler, | 2867 bool ok = alternatives_->at(0).node()->Emit(compiler, |
| 2780 &greedy_match_variant); | 2868 &greedy_match_trace); |
| 2781 macro_assembler->Bind(&greedy_match_failed); | 2869 macro_assembler->Bind(&greedy_match_failed); |
| 2782 if (!ok) { | 2870 if (!ok) { |
| 2783 greedy_loop_label.Unuse(); | 2871 greedy_loop_label.Unuse(); |
| 2784 return false; | 2872 return false; |
| 2785 } | 2873 } |
| 2786 } | 2874 } |
| 2787 | 2875 |
| 2788 Label second_choice; // For use in greedy matches. | 2876 Label second_choice; // For use in greedy matches. |
| 2789 macro_assembler->Bind(&second_choice); | 2877 macro_assembler->Bind(&second_choice); |
| 2790 | 2878 |
| 2791 int first_normal_choice = greedy_loop ? 1 : 0; | 2879 int first_normal_choice = greedy_loop ? 1 : 0; |
| 2792 | 2880 |
| 2793 int preload_characters = CalculatePreloadCharacters(compiler); | 2881 int preload_characters = CalculatePreloadCharacters(compiler); |
| 2794 bool preload_is_current = | 2882 bool preload_is_current = |
| 2795 (current_variant->characters_preloaded() == preload_characters); | 2883 (current_trace->characters_preloaded() == preload_characters); |
| 2796 bool preload_has_checked_bounds = preload_is_current; | 2884 bool preload_has_checked_bounds = preload_is_current; |
| 2797 | 2885 |
| 2798 AlternativeGenerationList alt_gens(choice_count); | 2886 AlternativeGenerationList alt_gens(choice_count); |
| 2799 | 2887 |
| 2800 // For now we just call all choices one after the other. The idea ultimately | 2888 // For now we just call all choices one after the other. The idea ultimately |
| 2801 // is to use the Dispatch table to try only the relevant ones. | 2889 // is to use the Dispatch table to try only the relevant ones. |
| 2802 for (int i = first_normal_choice; i < choice_count; i++) { | 2890 for (int i = first_normal_choice; i < choice_count; i++) { |
| 2803 GuardedAlternative alternative = alternatives_->at(i); | 2891 GuardedAlternative alternative = alternatives_->at(i); |
| 2804 AlternativeGeneration* alt_gen(alt_gens.at(i)); | 2892 AlternativeGeneration* alt_gen = alt_gens.at(i); |
| 2805 alt_gen->quick_check_details.set_characters(preload_characters); | 2893 alt_gen->quick_check_details.set_characters(preload_characters); |
| 2806 ZoneList<Guard*>* guards = alternative.guards(); | 2894 ZoneList<Guard*>* guards = alternative.guards(); |
| 2807 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2895 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2808 GenerationVariant new_variant(*current_variant); | 2896 Trace new_trace(*current_trace); |
| 2809 new_variant.set_characters_preloaded(preload_is_current ? | 2897 new_trace.set_characters_preloaded(preload_is_current ? |
| 2810 preload_characters : | 2898 preload_characters : |
| 2811 0); | 2899 0); |
| 2812 if (preload_has_checked_bounds) { | 2900 if (preload_has_checked_bounds) { |
| 2813 new_variant.set_bound_checked_up_to(preload_characters); | 2901 new_trace.set_bound_checked_up_to(preload_characters); |
| 2814 } | 2902 } |
| 2815 new_variant.quick_check_performed()->Clear(); | 2903 new_trace.quick_check_performed()->Clear(); |
| 2816 alt_gen->expects_preload = preload_is_current; | 2904 alt_gen->expects_preload = preload_is_current; |
| 2817 bool generate_full_check_inline = false; | 2905 bool generate_full_check_inline = false; |
| 2818 if (alternative.node()->EmitQuickCheck(compiler, | 2906 if (alternative.node()->EmitQuickCheck(compiler, |
| 2819 &new_variant, | 2907 &new_trace, |
| 2820 preload_has_checked_bounds, | 2908 preload_has_checked_bounds, |
| 2821 &alt_gen->possible_success, | 2909 &alt_gen->possible_success, |
| 2822 &alt_gen->quick_check_details, | 2910 &alt_gen->quick_check_details, |
| 2823 i < choice_count - 1)) { | 2911 i < choice_count - 1)) { |
| 2824 // Quick check was generated for this choice. | 2912 // Quick check was generated for this choice. |
| 2825 preload_is_current = true; | 2913 preload_is_current = true; |
| 2826 preload_has_checked_bounds = true; | 2914 preload_has_checked_bounds = true; |
| 2827 // On the last choice in the ChoiceNode we generated the quick | 2915 // On the last choice in the ChoiceNode we generated the quick |
| 2828 // check to fall through on possible success. So now we need to | 2916 // check to fall through on possible success. So now we need to |
| 2829 // generate the full check inline. | 2917 // generate the full check inline. |
| 2830 if (i == choice_count - 1) { | 2918 if (i == choice_count - 1) { |
| 2831 macro_assembler->Bind(&alt_gen->possible_success); | 2919 macro_assembler->Bind(&alt_gen->possible_success); |
| 2832 new_variant.set_quick_check_performed(&alt_gen->quick_check_details); | 2920 new_trace.set_quick_check_performed(&alt_gen->quick_check_details); |
| 2833 new_variant.set_characters_preloaded(preload_characters); | 2921 new_trace.set_characters_preloaded(preload_characters); |
| 2834 new_variant.set_bound_checked_up_to(preload_characters); | 2922 new_trace.set_bound_checked_up_to(preload_characters); |
| 2835 generate_full_check_inline = true; | 2923 generate_full_check_inline = true; |
| 2836 } | 2924 } |
| 2837 } else { | 2925 } else { |
| 2838 // No quick check was generated. Put the full code here. | 2926 // No quick check was generated. Put the full code here. |
| 2839 // If this is not the first choice then there could be slow checks from | 2927 // If this is not the first choice then there could be slow checks from |
| 2840 // previous cases that go here when they fail. There's no reason to | 2928 // previous cases that go here when they fail. There's no reason to |
| 2841 // insist that they preload characters since the slow check we are about | 2929 // insist that they preload characters since the slow check we are about |
| 2842 // to generate probably can't use it. | 2930 // to generate probably can't use it. |
| 2843 if (i != first_normal_choice) { | 2931 if (i != first_normal_choice) { |
| 2844 alt_gen->expects_preload = false; | 2932 alt_gen->expects_preload = false; |
| 2845 new_variant.set_characters_preloaded(0); | 2933 new_trace.set_characters_preloaded(0); |
| 2846 } | 2934 } |
| 2847 if (i < choice_count - 1) { | 2935 if (i < choice_count - 1) { |
| 2848 new_variant.set_backtrack(&alt_gen->after); | 2936 new_trace.set_backtrack(&alt_gen->after); |
| 2849 } | 2937 } |
| 2850 generate_full_check_inline = true; | 2938 generate_full_check_inline = true; |
| 2851 } | 2939 } |
| 2852 if (generate_full_check_inline) { | 2940 if (generate_full_check_inline) { |
| 2853 for (int j = 0; j < guard_count; j++) { | 2941 for (int j = 0; j < guard_count; j++) { |
| 2854 GenerateGuard(macro_assembler, guards->at(j), &new_variant); | 2942 GenerateGuard(macro_assembler, guards->at(j), &new_trace); |
| 2855 } | 2943 } |
| 2856 if (!alternative.node()->Emit(compiler, &new_variant)) { | 2944 if (!alternative.node()->Emit(compiler, &new_trace)) { |
| 2857 greedy_loop_label.Unuse(); | 2945 greedy_loop_label.Unuse(); |
| 2858 return false; | 2946 return false; |
| 2859 } | 2947 } |
| 2860 preload_is_current = false; | 2948 preload_is_current = false; |
| 2861 } | 2949 } |
| 2862 macro_assembler->Bind(&alt_gen->after); | 2950 macro_assembler->Bind(&alt_gen->after); |
| 2863 } | 2951 } |
| 2864 if (greedy_loop) { | 2952 if (greedy_loop) { |
| 2865 macro_assembler->Bind(&greedy_loop_label); | 2953 macro_assembler->Bind(&greedy_loop_label); |
| 2866 // If we have unwound to the bottom then backtrack. | 2954 // If we have unwound to the bottom then backtrack. |
| 2867 macro_assembler->CheckGreedyLoop(variant->backtrack()); | 2955 macro_assembler->CheckGreedyLoop(trace->backtrack()); |
| 2868 // Otherwise try the second priority at an earlier position. | 2956 // Otherwise try the second priority at an earlier position. |
| 2869 macro_assembler->AdvanceCurrentPosition(-text_length); | 2957 macro_assembler->AdvanceCurrentPosition(-text_length); |
| 2870 macro_assembler->GoTo(&second_choice); | 2958 macro_assembler->GoTo(&second_choice); |
| 2871 } | 2959 } |
| 2872 // At this point we need to generate slow checks for the alternatives where | 2960 // At this point we need to generate slow checks for the alternatives where |
| 2873 // the quick check was inlined. We can recognize these because the associated | 2961 // the quick check was inlined. We can recognize these because the associated |
| 2874 // label was bound. | 2962 // label was bound. |
| 2875 for (int i = first_normal_choice; i < choice_count - 1; i++) { | 2963 for (int i = first_normal_choice; i < choice_count - 1; i++) { |
| 2876 AlternativeGeneration* alt_gen = alt_gens.at(i); | 2964 AlternativeGeneration* alt_gen = alt_gens.at(i); |
| 2877 if (!EmitOutOfLineContinuation(compiler, | 2965 if (!EmitOutOfLineContinuation(compiler, |
| 2878 current_variant, | 2966 current_trace, |
| 2879 alternatives_->at(i), | 2967 alternatives_->at(i), |
| 2880 alt_gen, | 2968 alt_gen, |
| 2881 preload_characters, | 2969 preload_characters, |
| 2882 alt_gens.at(i + 1)->expects_preload)) { | 2970 alt_gens.at(i + 1)->expects_preload)) { |
| 2883 return false; | 2971 return false; |
| 2884 } | 2972 } |
| 2885 } | 2973 } |
| 2886 return true; | 2974 return true; |
| 2887 } | 2975 } |
| 2888 | 2976 |
| 2889 | 2977 |
| 2890 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, | 2978 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, |
| 2891 GenerationVariant* variant, | 2979 Trace* trace, |
| 2892 GuardedAlternative alternative, | 2980 GuardedAlternative alternative, |
| 2893 AlternativeGeneration* alt_gen, | 2981 AlternativeGeneration* alt_gen, |
| 2894 int preload_characters, | 2982 int preload_characters, |
| 2895 bool next_expects_preload) { | 2983 bool next_expects_preload) { |
| 2896 if (!alt_gen->possible_success.is_linked()) return true; | 2984 if (!alt_gen->possible_success.is_linked()) return true; |
| 2897 | 2985 |
| 2898 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2986 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2899 macro_assembler->Bind(&alt_gen->possible_success); | 2987 macro_assembler->Bind(&alt_gen->possible_success); |
| 2900 GenerationVariant out_of_line_variant(*variant); | 2988 Trace out_of_line_trace(*trace); |
| 2901 out_of_line_variant.set_characters_preloaded(preload_characters); | 2989 out_of_line_trace.set_characters_preloaded(preload_characters); |
| 2902 out_of_line_variant.set_quick_check_performed(&alt_gen->quick_check_details); | 2990 out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details); |
| 2903 ZoneList<Guard*>* guards = alternative.guards(); | 2991 ZoneList<Guard*>* guards = alternative.guards(); |
| 2904 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2992 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2905 if (next_expects_preload) { | 2993 if (next_expects_preload) { |
| 2906 Label reload_current_char; | 2994 Label reload_current_char; |
| 2907 out_of_line_variant.set_backtrack(&reload_current_char); | 2995 out_of_line_trace.set_backtrack(&reload_current_char); |
| 2908 for (int j = 0; j < guard_count; j++) { | 2996 for (int j = 0; j < guard_count; j++) { |
| 2909 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); | 2997 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
| 2910 } | 2998 } |
| 2911 bool ok = alternative.node()->Emit(compiler, &out_of_line_variant); | 2999 bool ok = alternative.node()->Emit(compiler, &out_of_line_trace); |
| 2912 macro_assembler->Bind(&reload_current_char); | 3000 macro_assembler->Bind(&reload_current_char); |
| 2913 // Reload the current character, since the next quick check expects that. | 3001 // Reload the current character, since the next quick check expects that. |
| 2914 // We don't need to check bounds here because we only get into this | 3002 // We don't need to check bounds here because we only get into this |
| 2915 // code through a quick check which already did the checked load. | 3003 // code through a quick check which already did the checked load. |
| 2916 macro_assembler->LoadCurrentCharacter(variant->cp_offset(), | 3004 macro_assembler->LoadCurrentCharacter(trace->cp_offset(), |
| 2917 NULL, | 3005 NULL, |
| 2918 false, | 3006 false, |
| 2919 preload_characters); | 3007 preload_characters); |
| 2920 macro_assembler->GoTo(&(alt_gen->after)); | 3008 macro_assembler->GoTo(&(alt_gen->after)); |
| 2921 return ok; | 3009 return ok; |
| 2922 } else { | 3010 } else { |
| 2923 out_of_line_variant.set_backtrack(&(alt_gen->after)); | 3011 out_of_line_trace.set_backtrack(&(alt_gen->after)); |
| 2924 for (int j = 0; j < guard_count; j++) { | 3012 for (int j = 0; j < guard_count; j++) { |
| 2925 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); | 3013 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
| 2926 } | 3014 } |
| 2927 return alternative.node()->Emit(compiler, &out_of_line_variant); | 3015 return alternative.node()->Emit(compiler, &out_of_line_trace); |
| 2928 } | 3016 } |
| 2929 } | 3017 } |
| 2930 | 3018 |
| 2931 | 3019 |
| 2932 bool ActionNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 3020 bool ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2933 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3021 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2934 LimitResult limit_result = LimitVersions(compiler, variant); | 3022 LimitResult limit_result = LimitVersions(compiler, trace); |
| 2935 if (limit_result == DONE) return true; | 3023 if (limit_result == DONE) return true; |
| 2936 if (limit_result == FAIL) return false; | 3024 if (limit_result == FAIL) return false; |
| 2937 ASSERT(limit_result == CONTINUE); | 3025 ASSERT(limit_result == CONTINUE); |
| 2938 | 3026 |
| 2939 RecursionCheck rc(compiler); | 3027 RecursionCheck rc(compiler); |
| 2940 | 3028 |
| 2941 switch (type_) { | 3029 switch (type_) { |
| 2942 case STORE_POSITION: { | 3030 case STORE_POSITION: { |
| 2943 GenerationVariant::DeferredCapture | 3031 Trace::DeferredCapture |
| 2944 new_capture(data_.u_position_register.reg, variant); | 3032 new_capture(data_.u_position_register.reg, trace); |
| 2945 GenerationVariant new_variant = *variant; | 3033 Trace new_trace = *trace; |
| 2946 new_variant.add_action(&new_capture); | 3034 new_trace.add_action(&new_capture); |
| 2947 return on_success()->Emit(compiler, &new_variant); | 3035 return on_success()->Emit(compiler, &new_trace); |
| 2948 } | 3036 } |
| 2949 case INCREMENT_REGISTER: { | 3037 case INCREMENT_REGISTER: { |
| 2950 GenerationVariant::DeferredIncrementRegister | 3038 Trace::DeferredIncrementRegister |
| 2951 new_increment(data_.u_increment_register.reg); | 3039 new_increment(data_.u_increment_register.reg); |
| 2952 GenerationVariant new_variant = *variant; | 3040 Trace new_trace = *trace; |
| 2953 new_variant.add_action(&new_increment); | 3041 new_trace.add_action(&new_increment); |
| 2954 return on_success()->Emit(compiler, &new_variant); | 3042 return on_success()->Emit(compiler, &new_trace); |
| 2955 } | 3043 } |
| 2956 case SET_REGISTER: { | 3044 case SET_REGISTER: { |
| 2957 GenerationVariant::DeferredSetRegister | 3045 Trace::DeferredSetRegister |
| 2958 new_set(data_.u_store_register.reg, data_.u_store_register.value); | 3046 new_set(data_.u_store_register.reg, data_.u_store_register.value); |
| 2959 GenerationVariant new_variant = *variant; | 3047 Trace new_trace = *trace; |
| 2960 new_variant.add_action(&new_set); | 3048 new_trace.add_action(&new_set); |
| 2961 return on_success()->Emit(compiler, &new_variant); | 3049 return on_success()->Emit(compiler, &new_trace); |
| 3050 } |
| 3051 case CLEAR_CAPTURES: { |
| 3052 Trace::DeferredClearCaptures |
| 3053 new_capture(Interval(data_.u_clear_captures.range_from, |
| 3054 data_.u_clear_captures.range_to)); |
| 3055 Trace new_trace = *trace; |
| 3056 new_trace.add_action(&new_capture); |
| 3057 return on_success()->Emit(compiler, &new_trace); |
| 2962 } | 3058 } |
| 2963 case BEGIN_SUBMATCH: | 3059 case BEGIN_SUBMATCH: |
| 2964 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 3060 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
| 2965 assembler->WriteCurrentPositionToRegister( | 3061 assembler->WriteCurrentPositionToRegister( |
| 2966 data_.u_submatch.current_position_register, 0); | 3062 data_.u_submatch.current_position_register, 0); |
| 2967 assembler->WriteStackPointerToRegister( | 3063 assembler->WriteStackPointerToRegister( |
| 2968 data_.u_submatch.stack_pointer_register); | 3064 data_.u_submatch.stack_pointer_register); |
| 2969 return on_success()->Emit(compiler, variant); | 3065 return on_success()->Emit(compiler, trace); |
| 3066 case EMPTY_MATCH_CHECK: { |
| 3067 int start_pos_reg = data_.u_empty_match_check.start_register; |
| 3068 int stored_pos = 0; |
| 3069 int rep_reg = data_.u_empty_match_check.repetition_register; |
| 3070 bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister); |
| 3071 bool know_dist = trace->GetStoredPosition(start_pos_reg, &stored_pos); |
| 3072 if (know_dist && !has_minimum && stored_pos == trace->cp_offset()) { |
| 3073 // If we know we haven't advanced and there is no minimum we |
| 3074 // can just backtrack immediately. |
| 3075 assembler->GoTo(trace->backtrack()); |
| 3076 return true; |
| 3077 } else if (know_dist && stored_pos < trace->cp_offset()) { |
| 3078 // If we know we've advanced we can generate the continuation |
| 3079 // immediately. |
| 3080 return on_success()->Emit(compiler, trace); |
| 3081 } |
| 3082 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
| 3083 Label skip_empty_check; |
| 3084 // If we have a minimum number of repetitions we check the current |
| 3085 // number first and skip the empty check if it's not enough. |
| 3086 if (has_minimum) { |
| 3087 int limit = data_.u_empty_match_check.repetition_limit; |
| 3088 assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check); |
| 3089 } |
| 3090 // If the match is empty we bail out, otherwise we fall through |
| 3091 // to the on-success continuation. |
| 3092 assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register, |
| 3093 trace->backtrack()); |
| 3094 assembler->Bind(&skip_empty_check); |
| 3095 return on_success()->Emit(compiler, trace); |
| 3096 } |
| 2970 case POSITIVE_SUBMATCH_SUCCESS: | 3097 case POSITIVE_SUBMATCH_SUCCESS: |
| 2971 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 3098 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
| 2972 // TODO(erikcorry): Implement support. | 3099 // TODO(erikcorry): Implement support. |
| 2973 if (info()->follows_word_interest || | 3100 if (info()->follows_word_interest || |
| 2974 info()->follows_newline_interest || | 3101 info()->follows_newline_interest || |
| 2975 info()->follows_start_interest) { | 3102 info()->follows_start_interest) { |
| 2976 return false; | 3103 return false; |
| 2977 } | 3104 } |
| 2978 if (info()->at_end) { | 3105 if (info()->at_end) { |
| 2979 Label at_end; | 3106 Label at_end; |
| 2980 // Load current character jumps to the label if we are beyond the string | 3107 // Load current character jumps to the label if we are beyond the string |
| 2981 // end. | 3108 // end. |
| 2982 assembler->LoadCurrentCharacter(0, &at_end); | 3109 assembler->LoadCurrentCharacter(0, &at_end); |
| 2983 assembler->GoTo(variant->backtrack()); | 3110 assembler->GoTo(trace->backtrack()); |
| 2984 assembler->Bind(&at_end); | 3111 assembler->Bind(&at_end); |
| 2985 } | 3112 } |
| 2986 assembler->ReadCurrentPositionFromRegister( | 3113 assembler->ReadCurrentPositionFromRegister( |
| 2987 data_.u_submatch.current_position_register); | 3114 data_.u_submatch.current_position_register); |
| 2988 assembler->ReadStackPointerFromRegister( | 3115 assembler->ReadStackPointerFromRegister( |
| 2989 data_.u_submatch.stack_pointer_register); | 3116 data_.u_submatch.stack_pointer_register); |
| 2990 return on_success()->Emit(compiler, variant); | 3117 return on_success()->Emit(compiler, trace); |
| 2991 default: | 3118 default: |
| 2992 UNREACHABLE(); | 3119 UNREACHABLE(); |
| 2993 return false; | 3120 return false; |
| 2994 } | 3121 } |
| 2995 } | 3122 } |
| 2996 | 3123 |
| 2997 | 3124 |
| 2998 bool BackReferenceNode::Emit(RegExpCompiler* compiler, | 3125 bool BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2999 GenerationVariant* variant) { | |
| 3000 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3126 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 3001 if (!variant->is_trivial()) { | 3127 if (!trace->is_trivial()) { |
| 3002 return variant->Flush(compiler, this); | 3128 return trace->Flush(compiler, this); |
| 3003 } | 3129 } |
| 3004 | 3130 |
| 3005 LimitResult limit_result = LimitVersions(compiler, variant); | 3131 LimitResult limit_result = LimitVersions(compiler, trace); |
| 3006 if (limit_result == DONE) return true; | 3132 if (limit_result == DONE) return true; |
| 3007 if (limit_result == FAIL) return false; | 3133 if (limit_result == FAIL) return false; |
| 3008 ASSERT(limit_result == CONTINUE); | 3134 ASSERT(limit_result == CONTINUE); |
| 3009 | 3135 |
| 3010 RecursionCheck rc(compiler); | 3136 RecursionCheck rc(compiler); |
| 3011 | 3137 |
| 3012 ASSERT_EQ(start_reg_ + 1, end_reg_); | 3138 ASSERT_EQ(start_reg_ + 1, end_reg_); |
| 3013 if (info()->at_end) { | 3139 if (info()->at_end) { |
| 3014 // If we are constrained to match at the end of the input then succeed | 3140 // If we are constrained to match at the end of the input then succeed |
| 3015 // iff the back reference is empty. | 3141 // iff the back reference is empty. |
| 3016 assembler->CheckNotRegistersEqual(start_reg_, | 3142 assembler->CheckNotRegistersEqual(start_reg_, |
| 3017 end_reg_, | 3143 end_reg_, |
| 3018 variant->backtrack()); | 3144 trace->backtrack()); |
| 3019 } else { | 3145 } else { |
| 3020 if (compiler->ignore_case()) { | 3146 if (compiler->ignore_case()) { |
| 3021 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, | 3147 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, |
| 3022 variant->backtrack()); | 3148 trace->backtrack()); |
| 3023 } else { | 3149 } else { |
| 3024 assembler->CheckNotBackReference(start_reg_, variant->backtrack()); | 3150 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); |
| 3025 } | 3151 } |
| 3026 } | 3152 } |
| 3027 return on_success()->Emit(compiler, variant); | 3153 return on_success()->Emit(compiler, trace); |
| 3028 } | 3154 } |
| 3029 | 3155 |
| 3030 | 3156 |
| 3031 // ------------------------------------------------------------------- | 3157 // ------------------------------------------------------------------- |
| 3032 // Dot/dotty output | 3158 // Dot/dotty output |
| 3033 | 3159 |
| 3034 | 3160 |
| 3035 #ifdef DEBUG | 3161 #ifdef DEBUG |
| 3036 | 3162 |
| 3037 | 3163 |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3279 stream()->Add("label=\"$%i:=$pos\", shape=octagon", | 3405 stream()->Add("label=\"$%i:=$pos\", shape=octagon", |
| 3280 that->data_.u_position_register.reg); | 3406 that->data_.u_position_register.reg); |
| 3281 break; | 3407 break; |
| 3282 case ActionNode::BEGIN_SUBMATCH: | 3408 case ActionNode::BEGIN_SUBMATCH: |
| 3283 stream()->Add("label=\"$%i:=$pos,begin\", shape=septagon", | 3409 stream()->Add("label=\"$%i:=$pos,begin\", shape=septagon", |
| 3284 that->data_.u_submatch.current_position_register); | 3410 that->data_.u_submatch.current_position_register); |
| 3285 break; | 3411 break; |
| 3286 case ActionNode::POSITIVE_SUBMATCH_SUCCESS: | 3412 case ActionNode::POSITIVE_SUBMATCH_SUCCESS: |
| 3287 stream()->Add("label=\"escape\", shape=septagon"); | 3413 stream()->Add("label=\"escape\", shape=septagon"); |
| 3288 break; | 3414 break; |
| 3415 case ActionNode::EMPTY_MATCH_CHECK: |
| 3416 stream()->Add("label=\"$%i=$pos?,$%i<%i?\", shape=septagon", |
| 3417 that->data_.u_empty_match_check.start_register, |
| 3418 that->data_.u_empty_match_check.repetition_register, |
| 3419 that->data_.u_empty_match_check.repetition_limit); |
| 3420 break; |
| 3421 case ActionNode::CLEAR_CAPTURES: { |
| 3422 stream()->Add("label=\"clear $%i to $%i\", shape=septagon", |
| 3423 that->data_.u_clear_captures.range_from, |
| 3424 that->data_.u_clear_captures.range_to); |
| 3425 break; |
| 3426 } |
| 3289 } | 3427 } |
| 3290 stream()->Add("];\n"); | 3428 stream()->Add("];\n"); |
| 3291 PrintAttributes(that); | 3429 PrintAttributes(that); |
| 3292 RegExpNode* successor = that->on_success(); | 3430 RegExpNode* successor = that->on_success(); |
| 3293 stream()->Add(" n%p -> n%p;\n", that, successor); | 3431 stream()->Add(" n%p -> n%p;\n", that, successor); |
| 3294 Visit(successor); | 3432 Visit(successor); |
| 3295 } | 3433 } |
| 3296 | 3434 |
| 3297 | 3435 |
| 3298 class DispatchTableDumper { | 3436 class DispatchTableDumper { |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3504 // where max_match is zero the parser has removed the quantifier if min was | 3642 // where max_match is zero the parser has removed the quantifier if min was |
| 3505 // > 0 and removed the atom if min was 0. See AddQuantifierToAtom. | 3643 // > 0 and removed the atom if min was 0. See AddQuantifierToAtom. |
| 3506 | 3644 |
| 3507 // If we know that we cannot match zero length then things are a little | 3645 // If we know that we cannot match zero length then things are a little |
| 3508 // simpler since we don't need to make the special zero length match check | 3646 // simpler since we don't need to make the special zero length match check |
| 3509 // from step 2.1. If the min and max are small we can unroll a little in | 3647 // from step 2.1. If the min and max are small we can unroll a little in |
| 3510 // this case. | 3648 // this case. |
| 3511 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} | 3649 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} |
| 3512 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} | 3650 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} |
| 3513 if (max == 0) return on_success; // This can happen due to recursion. | 3651 if (max == 0) return on_success; // This can happen due to recursion. |
| 3514 if (body->min_match() > 0) { | 3652 bool body_can_be_empty = (body->min_match() == 0); |
| 3653 int body_start_reg = RegExpCompiler::kNoRegister; |
| 3654 Interval capture_registers = body->CaptureRegisters(); |
| 3655 bool needs_capture_clearing = !capture_registers.is_empty(); |
| 3656 if (body_can_be_empty) { |
| 3657 body_start_reg = compiler->AllocateRegister(); |
| 3658 } else if (!needs_capture_clearing) { |
| 3659 // Only unroll if there are no captures and the body can't be |
| 3660 // empty. |
| 3515 if (min > 0 && min <= kMaxUnrolledMinMatches) { | 3661 if (min > 0 && min <= kMaxUnrolledMinMatches) { |
| 3516 int new_max = (max == kInfinity) ? max : max - min; | 3662 int new_max = (max == kInfinity) ? max : max - min; |
| 3517 // Recurse once to get the loop or optional matches after the fixed ones. | 3663 // Recurse once to get the loop or optional matches after the fixed ones. |
| 3518 RegExpNode* answer = | 3664 RegExpNode* answer = |
| 3519 ToNode(0, new_max, is_greedy, body, compiler, on_success); | 3665 ToNode(0, new_max, is_greedy, body, compiler, on_success); |
| 3520 // Unroll the forced matches from 0 to min. This can cause chains of | 3666 // Unroll the forced matches from 0 to min. This can cause chains of |
| 3521 // TextNodes (which the parser does not generate). These should be | 3667 // TextNodes (which the parser does not generate). These should be |
| 3522 // combined if it turns out they hinder good code generation. | 3668 // combined if it turns out they hinder good code generation. |
| 3523 for (int i = 0; i < min; i++) { | 3669 for (int i = 0; i < min; i++) { |
| 3524 answer = body->ToNode(compiler, answer); | 3670 answer = body->ToNode(compiler, answer); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3541 answer))); | 3687 answer))); |
| 3542 } | 3688 } |
| 3543 answer = alternation; | 3689 answer = alternation; |
| 3544 } | 3690 } |
| 3545 return answer; | 3691 return answer; |
| 3546 } | 3692 } |
| 3547 } | 3693 } |
| 3548 bool has_min = min > 0; | 3694 bool has_min = min > 0; |
| 3549 bool has_max = max < RegExpTree::kInfinity; | 3695 bool has_max = max < RegExpTree::kInfinity; |
| 3550 bool needs_counter = has_min || has_max; | 3696 bool needs_counter = has_min || has_max; |
| 3551 int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1; | 3697 int reg_ctr = needs_counter |
| 3698 ? compiler->AllocateRegister() |
| 3699 : RegExpCompiler::kNoRegister; |
| 3552 LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0); | 3700 LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0); |
| 3553 RegExpNode* loop_return = needs_counter | 3701 RegExpNode* loop_return = needs_counter |
| 3554 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) | 3702 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) |
| 3555 : static_cast<RegExpNode*>(center); | 3703 : static_cast<RegExpNode*>(center); |
| 3704 if (body_can_be_empty) { |
| 3705 // If the body can be empty we need to check if it was and then |
| 3706 // backtrack. |
| 3707 loop_return = ActionNode::EmptyMatchCheck(body_start_reg, |
| 3708 reg_ctr, |
| 3709 min, |
| 3710 loop_return); |
| 3711 } |
| 3556 RegExpNode* body_node = body->ToNode(compiler, loop_return); | 3712 RegExpNode* body_node = body->ToNode(compiler, loop_return); |
| 3713 if (body_can_be_empty) { |
| 3714 // If the body can be empty we need to store the start position |
| 3715 // so we can bail out if it was empty. |
| 3716 body_node = ActionNode::StorePosition(body_start_reg, body_node); |
| 3717 } |
| 3718 if (needs_capture_clearing) { |
| 3719 // Before entering the body of this loop we need to clear captures. |
| 3720 body_node = ActionNode::ClearCaptures(capture_registers, body_node); |
| 3721 } |
| 3557 GuardedAlternative body_alt(body_node); | 3722 GuardedAlternative body_alt(body_node); |
| 3558 if (has_max) { | 3723 if (has_max) { |
| 3559 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max); | 3724 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max); |
| 3560 body_alt.AddGuard(body_guard); | 3725 body_alt.AddGuard(body_guard); |
| 3561 } | 3726 } |
| 3562 GuardedAlternative rest_alt(on_success); | 3727 GuardedAlternative rest_alt(on_success); |
| 3563 if (has_min) { | 3728 if (has_min) { |
| 3564 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min); | 3729 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min); |
| 3565 rest_alt.AddGuard(rest_guard); | 3730 rest_alt.AddGuard(rest_guard); |
| 3566 } | 3731 } |
| (...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4387 EmbeddedVector<byte, 1024> codes; | 4552 EmbeddedVector<byte, 1024> codes; |
| 4388 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4553 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 4389 return compiler.Assemble(¯o_assembler, | 4554 return compiler.Assemble(¯o_assembler, |
| 4390 node, | 4555 node, |
| 4391 data->capture_count, | 4556 data->capture_count, |
| 4392 pattern); | 4557 pattern); |
| 4393 } | 4558 } |
| 4394 | 4559 |
| 4395 | 4560 |
| 4396 }} // namespace v8::internal | 4561 }} // namespace v8::internal |
| OLD | NEW |