Chromium Code Reviews| 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 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 | 291 |
| 292 | 292 |
| 293 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, | 293 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, |
| 294 Handle<String> subject, | 294 Handle<String> subject, |
| 295 Handle<Object> index) { | 295 Handle<Object> index) { |
| 296 switch (regexp->TypeTag()) { | 296 switch (regexp->TypeTag()) { |
| 297 case JSRegExp::ATOM: | 297 case JSRegExp::ATOM: |
| 298 return AtomExec(regexp, subject, index); | 298 return AtomExec(regexp, subject, index); |
| 299 case JSRegExp::IRREGEXP: { | 299 case JSRegExp::IRREGEXP: { |
| 300 Handle<Object> result = IrregexpExec(regexp, subject, index); | 300 Handle<Object> result = IrregexpExec(regexp, subject, index); |
| 301 if (!result.is_null() || Top::has_pending_exception()) { | 301 if (result.is_null()) ASSERT(Top::has_pending_exception()); |
| 302 return result; | 302 return result; |
| 303 } | |
| 304 // We couldn't handle the regexp using Irregexp, so fall back | |
| 305 // on JSCRE. | |
| 306 // Reset the JSRegExp to use JSCRE. | |
| 307 JscrePrepare(regexp, | |
| 308 Handle<String>(regexp->Pattern()), | |
| 309 regexp->GetFlags()); | |
| 310 // Fall-through to JSCRE. | |
| 311 } | 303 } |
| 312 case JSRegExp::JSCRE: | 304 case JSRegExp::JSCRE: |
| 313 if (FLAG_disable_jscre) { | |
| 314 UNIMPLEMENTED(); | |
| 315 } | |
| 316 return JscreExec(regexp, subject, index); | 305 return JscreExec(regexp, subject, index); |
| 317 default: | 306 default: |
| 318 UNREACHABLE(); | 307 UNREACHABLE(); |
| 319 return Handle<Object>::null(); | 308 return Handle<Object>::null(); |
| 320 } | 309 } |
| 321 } | 310 } |
| 322 | 311 |
| 323 | 312 |
| 324 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, | 313 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, |
| 325 Handle<String> subject) { | 314 Handle<String> subject) { |
| 326 switch (regexp->TypeTag()) { | 315 switch (regexp->TypeTag()) { |
| 327 case JSRegExp::ATOM: | 316 case JSRegExp::ATOM: |
| 328 return AtomExecGlobal(regexp, subject); | 317 return AtomExecGlobal(regexp, subject); |
| 329 case JSRegExp::IRREGEXP: { | 318 case JSRegExp::IRREGEXP: { |
| 330 Handle<Object> result = IrregexpExecGlobal(regexp, subject); | 319 Handle<Object> result = IrregexpExecGlobal(regexp, subject); |
| 331 if (!result.is_null() || Top::has_pending_exception()) { | 320 if (result.is_null()) ASSERT(Top::has_pending_exception()); |
| 332 return result; | 321 return result; |
| 333 } | |
| 334 // Empty handle as result but no exception thrown means that | |
| 335 // the regexp contains features not yet handled by the irregexp | |
| 336 // compiler. | |
| 337 // We have to fall back on JSCRE. Reset the JSRegExp to use JSCRE. | |
| 338 JscrePrepare(regexp, | |
| 339 Handle<String>(regexp->Pattern()), | |
| 340 regexp->GetFlags()); | |
| 341 // Fall-through to JSCRE. | |
| 342 } | 322 } |
| 343 case JSRegExp::JSCRE: | 323 case JSRegExp::JSCRE: |
| 344 if (FLAG_disable_jscre) { | |
| 345 UNIMPLEMENTED(); | |
| 346 } | |
| 347 return JscreExecGlobal(regexp, subject); | 324 return JscreExecGlobal(regexp, subject); |
| 348 default: | 325 default: |
| 349 UNREACHABLE(); | 326 UNREACHABLE(); |
| 350 return Handle<Object>::null(); | 327 return Handle<Object>::null(); |
| 351 } | 328 } |
| 352 } | 329 } |
| 353 | 330 |
| 354 | 331 |
| 355 // RegExp Atom implementation: Simple string search using indexOf. | 332 // RegExp Atom implementation: Simple string search using indexOf. |
| 356 | 333 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 malloc_failure = Failure::Exception(); | 430 malloc_failure = Failure::Exception(); |
| 454 *code = v8::jscre::jsRegExpCompile(pattern->GetTwoByteData(), | 431 *code = v8::jscre::jsRegExpCompile(pattern->GetTwoByteData(), |
| 455 pattern->length(), | 432 pattern->length(), |
| 456 case_option, | 433 case_option, |
| 457 multiline_option, | 434 multiline_option, |
| 458 number_of_captures, | 435 number_of_captures, |
| 459 error_message, | 436 error_message, |
| 460 &JSREMalloc, | 437 &JSREMalloc, |
| 461 &JSREFree); | 438 &JSREFree); |
| 462 if (*code == NULL && (malloc_failure->IsRetryAfterGC() || | 439 if (*code == NULL && (malloc_failure->IsRetryAfterGC() || |
| 463 malloc_failure->IsOutOfMemoryFailure())) { | 440 malloc_failure->IsOutOfMemoryFailure())) { |
| 464 return malloc_failure; | 441 return malloc_failure; |
| 465 } else { | 442 } else { |
| 466 // It doesn't matter which object we return here, we just need to return | 443 // It doesn't matter which object we return here, we just need to return |
| 467 // a non-failure to indicate to the GC-retry code that there was no | 444 // a non-failure to indicate to the GC-retry code that there was no |
| 468 // allocation failure. | 445 // allocation failure. |
| 469 return pattern; | 446 return pattern; |
| 470 } | 447 } |
| 471 } | 448 } |
| 472 | 449 |
| 473 | 450 |
| (...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1191 cons.BuildTable(this); | 1168 cons.BuildTable(this); |
| 1192 } | 1169 } |
| 1193 return table_; | 1170 return table_; |
| 1194 } | 1171 } |
| 1195 | 1172 |
| 1196 | 1173 |
| 1197 class RegExpCompiler { | 1174 class RegExpCompiler { |
| 1198 public: | 1175 public: |
| 1199 RegExpCompiler(int capture_count, bool ignore_case, bool is_ascii); | 1176 RegExpCompiler(int capture_count, bool ignore_case, bool is_ascii); |
| 1200 | 1177 |
| 1201 int AllocateRegister() { return next_register_++; } | 1178 int AllocateRegister() { |
| 1179 if (next_register_ >= RegExpMacroAssembler::kMaxRegister) { | |
| 1180 reg_exp_too_big_ = true; | |
| 1181 return next_register_; | |
| 1182 } | |
| 1183 return next_register_++; | |
| 1184 } | |
| 1202 | 1185 |
| 1203 Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler, | 1186 Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler, |
| 1204 RegExpNode* start, | 1187 RegExpNode* start, |
| 1205 int capture_count, | 1188 int capture_count, |
| 1206 Handle<String> pattern); | 1189 Handle<String> pattern); |
| 1207 | 1190 |
| 1208 inline void AddWork(RegExpNode* node) { work_list_->Add(node); } | 1191 inline void AddWork(RegExpNode* node) { work_list_->Add(node); } |
| 1209 | 1192 |
| 1210 static const int kImplementationOffset = 0; | 1193 static const int kImplementationOffset = 0; |
| 1211 static const int kNumberOfRegistersOffset = 0; | 1194 static const int kNumberOfRegistersOffset = 0; |
| 1212 static const int kCodeOffset = 1; | 1195 static const int kCodeOffset = 1; |
| 1213 | 1196 |
| 1214 RegExpMacroAssembler* macro_assembler() { return macro_assembler_; } | 1197 RegExpMacroAssembler* macro_assembler() { return macro_assembler_; } |
| 1215 EndNode* accept() { return accept_; } | 1198 EndNode* accept() { return accept_; } |
| 1216 | 1199 |
| 1217 static const int kMaxRecursion = 100; | 1200 static const int kMaxRecursion = 100; |
| 1218 inline int recursion_depth() { return recursion_depth_; } | 1201 inline int recursion_depth() { return recursion_depth_; } |
| 1219 inline void IncrementRecursionDepth() { recursion_depth_++; } | 1202 inline void IncrementRecursionDepth() { recursion_depth_++; } |
| 1220 inline void DecrementRecursionDepth() { recursion_depth_--; } | 1203 inline void DecrementRecursionDepth() { recursion_depth_--; } |
| 1204 | |
| 1205 void SetRegExpTooBig() { reg_exp_too_big_ = true; } | |
| 1221 | 1206 |
| 1222 inline bool ignore_case() { return ignore_case_; } | 1207 inline bool ignore_case() { return ignore_case_; } |
| 1223 inline bool ascii() { return ascii_; } | 1208 inline bool ascii() { return ascii_; } |
| 1224 | 1209 |
| 1225 static const int kNoRegister = -1; | 1210 static const int kNoRegister = -1; |
| 1226 private: | 1211 private: |
| 1227 EndNode* accept_; | 1212 EndNode* accept_; |
| 1228 int next_register_; | 1213 int next_register_; |
| 1229 List<RegExpNode*>* work_list_; | 1214 List<RegExpNode*>* work_list_; |
| 1230 int recursion_depth_; | 1215 int recursion_depth_; |
| 1231 RegExpMacroAssembler* macro_assembler_; | 1216 RegExpMacroAssembler* macro_assembler_; |
| 1232 bool ignore_case_; | 1217 bool ignore_case_; |
| 1233 bool ascii_; | 1218 bool ascii_; |
| 1219 bool reg_exp_too_big_; | |
| 1234 }; | 1220 }; |
| 1235 | 1221 |
| 1236 | 1222 |
| 1237 class RecursionCheck { | 1223 class RecursionCheck { |
| 1238 public: | 1224 public: |
| 1239 explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { | 1225 explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { |
| 1240 compiler->IncrementRecursionDepth(); | 1226 compiler->IncrementRecursionDepth(); |
| 1241 } | 1227 } |
| 1242 ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } | 1228 ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } |
| 1243 private: | 1229 private: |
| 1244 RegExpCompiler* compiler_; | 1230 RegExpCompiler* compiler_; |
| 1245 }; | 1231 }; |
| 1246 | 1232 |
| 1247 | 1233 |
| 1234 static Handle<FixedArray> IrregexpRegExpTooBig(Handle<String> pattern) { | |
| 1235 Handle<JSArray> array = Factory::NewJSArray(2); | |
| 1236 SetElement(array, 0, pattern); | |
| 1237 const char* message = "RegExp too big"; | |
| 1238 SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(message))); | |
| 1239 Handle<Object> regexp_err = | |
| 1240 Factory::NewSyntaxError("malformed_regexp", array); | |
| 1241 Top::Throw(*regexp_err); | |
| 1242 return Handle<FixedArray>(); | |
| 1243 } | |
| 1244 | |
| 1245 | |
| 1248 // Attempts to compile the regexp using an Irregexp code generator. Returns | 1246 // Attempts to compile the regexp using an Irregexp code generator. Returns |
| 1249 // a fixed array or a null handle depending on whether it succeeded. | 1247 // a fixed array or a null handle depending on whether it succeeded. |
| 1250 RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case, bool ascii) | 1248 RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case, bool ascii) |
| 1251 : next_register_(2 * (capture_count + 1)), | 1249 : next_register_(2 * (capture_count + 1)), |
| 1252 work_list_(NULL), | 1250 work_list_(NULL), |
| 1253 recursion_depth_(0), | 1251 recursion_depth_(0), |
| 1254 ignore_case_(ignore_case), | 1252 ignore_case_(ignore_case), |
| 1255 ascii_(ascii) { | 1253 ascii_(ascii), |
| 1254 reg_exp_too_big_(false) { | |
| 1256 accept_ = new EndNode(EndNode::ACCEPT); | 1255 accept_ = new EndNode(EndNode::ACCEPT); |
| 1256 ASSERT(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister); | |
| 1257 } | 1257 } |
| 1258 | 1258 |
| 1259 | 1259 |
| 1260 Handle<FixedArray> RegExpCompiler::Assemble( | 1260 Handle<FixedArray> RegExpCompiler::Assemble( |
| 1261 RegExpMacroAssembler* macro_assembler, | 1261 RegExpMacroAssembler* macro_assembler, |
| 1262 RegExpNode* start, | 1262 RegExpNode* start, |
| 1263 int capture_count, | 1263 int capture_count, |
| 1264 Handle<String> pattern) { | 1264 Handle<String> pattern) { |
| 1265 #ifdef DEBUG | 1265 #ifdef DEBUG |
| 1266 if (FLAG_trace_regexp_assembler) | 1266 if (FLAG_trace_regexp_assembler) |
| 1267 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); | 1267 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); |
| 1268 else | 1268 else |
| 1269 #endif | 1269 #endif |
| 1270 macro_assembler_ = macro_assembler; | 1270 macro_assembler_ = macro_assembler; |
| 1271 List <RegExpNode*> work_list(0); | 1271 List <RegExpNode*> work_list(0); |
| 1272 work_list_ = &work_list; | 1272 work_list_ = &work_list; |
| 1273 Label fail; | 1273 Label fail; |
| 1274 macro_assembler->PushBacktrack(&fail); | 1274 macro_assembler->PushBacktrack(&fail); |
| 1275 Trace new_trace; | 1275 Trace new_trace; |
| 1276 if (!start->Emit(this, &new_trace)) { | 1276 start->Emit(this, &new_trace); |
| 1277 fail.Unuse(); | |
| 1278 return Handle<FixedArray>::null(); | |
| 1279 } | |
| 1280 macro_assembler_->Bind(&fail); | 1277 macro_assembler_->Bind(&fail); |
| 1281 macro_assembler_->Fail(); | 1278 macro_assembler_->Fail(); |
| 1282 while (!work_list.is_empty()) { | 1279 while (!work_list.is_empty()) { |
|
Lasse Reichstein
2009/01/26 13:48:53
You could bail out of this loop if the regexp is t
Erik Corry
2009/01/26 19:59:21
Unfortunately I can't because there are labels tha
| |
| 1283 if (!work_list.RemoveLast()->Emit(this, &new_trace)) { | 1280 work_list.RemoveLast()->Emit(this, &new_trace); |
| 1284 return Handle<FixedArray>::null(); | |
| 1285 } | |
| 1286 } | 1281 } |
| 1282 if (reg_exp_too_big_) return IrregexpRegExpTooBig(pattern); | |
| 1287 Handle<FixedArray> array = | 1283 Handle<FixedArray> array = |
| 1288 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); | 1284 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); |
| 1289 array->set(RegExpImpl::kIrregexpImplementationIndex, | 1285 array->set(RegExpImpl::kIrregexpImplementationIndex, |
| 1290 Smi::FromInt(macro_assembler_->Implementation())); | 1286 Smi::FromInt(macro_assembler_->Implementation())); |
| 1291 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, | 1287 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, |
| 1292 Smi::FromInt(next_register_)); | 1288 Smi::FromInt(next_register_)); |
| 1293 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, | 1289 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, |
| 1294 Smi::FromInt(capture_count)); | 1290 Smi::FromInt(capture_count)); |
| 1295 Handle<Object> code = macro_assembler_->GetCode(pattern); | 1291 Handle<Object> code = macro_assembler_->GetCode(pattern); |
| 1296 array->set(RegExpImpl::kIrregexpCodeIndex, *code); | 1292 array->set(RegExpImpl::kIrregexpCodeIndex, *code); |
| 1297 work_list_ = NULL; | 1293 work_list_ = NULL; |
| 1298 #ifdef DEBUG | 1294 #ifdef DEBUG |
| 1299 if (FLAG_trace_regexp_assembler) { | 1295 if (FLAG_trace_regexp_assembler) { |
| 1300 delete macro_assembler_; | 1296 delete macro_assembler_; |
| 1301 } | 1297 } |
| 1302 #endif | 1298 #endif |
| 1303 return array; | 1299 return array; |
| 1304 } | 1300 } |
| 1305 | 1301 |
| 1302 | |
| 1306 bool Trace::DeferredAction::Mentions(int that) { | 1303 bool Trace::DeferredAction::Mentions(int that) { |
| 1307 if (type() == ActionNode::CLEAR_CAPTURES) { | 1304 if (type() == ActionNode::CLEAR_CAPTURES) { |
| 1308 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); | 1305 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); |
| 1309 return range.Contains(that); | 1306 return range.Contains(that); |
| 1310 } else { | 1307 } else { |
| 1311 return reg() == that; | 1308 return reg() == that; |
| 1312 } | 1309 } |
| 1313 } | 1310 } |
| 1314 | 1311 |
| 1315 | 1312 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1458 } else if (value != 0) { | 1455 } else if (value != 0) { |
| 1459 assembler->AdvanceRegister(reg, value); | 1456 assembler->AdvanceRegister(reg, value); |
| 1460 } | 1457 } |
| 1461 } | 1458 } |
| 1462 } | 1459 } |
| 1463 | 1460 |
| 1464 | 1461 |
| 1465 // This is called as we come into a loop choice node and some other tricky | 1462 // This is called as we come into a loop choice node and some other tricky |
| 1466 // nodes. It normalizes the state of the code generator to ensure we can | 1463 // nodes. It normalizes the state of the code generator to ensure we can |
| 1467 // generate generic code. | 1464 // generate generic code. |
| 1468 bool Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { | 1465 void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
| 1469 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1466 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1470 | 1467 |
| 1471 ASSERT(actions_ != NULL || | 1468 ASSERT(actions_ != NULL || |
| 1472 cp_offset_ != 0 || | 1469 cp_offset_ != 0 || |
| 1473 backtrack() != NULL || | 1470 backtrack() != NULL || |
| 1474 characters_preloaded_ != 0 || | 1471 characters_preloaded_ != 0 || |
| 1475 quick_check_performed_.characters() != 0 || | 1472 quick_check_performed_.characters() != 0 || |
| 1476 bound_checked_up_to_ != 0); | 1473 bound_checked_up_to_ != 0); |
| 1477 | 1474 |
| 1478 if (actions_ == NULL && backtrack() == NULL) { | 1475 if (actions_ == NULL && backtrack() == NULL) { |
| 1479 // Here we just have some deferred cp advances to fix and we are back to | 1476 // Here we just have some deferred cp advances to fix and we are back to |
| 1480 // a normal situation. We may also have to forget some information gained | 1477 // a normal situation. We may also have to forget some information gained |
| 1481 // through a quick check that was already performed. | 1478 // through a quick check that was already performed. |
| 1482 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); | 1479 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); |
| 1483 // Create a new trivial state and generate the node with that. | 1480 // Create a new trivial state and generate the node with that. |
| 1484 Trace new_state; | 1481 Trace new_state; |
| 1485 return successor->Emit(compiler, &new_state); | 1482 successor->Emit(compiler, &new_state); |
| 1483 return; | |
|
Lasse Reichstein
2009/01/26 13:48:53
The return is superfluous.
Erik Corry
2009/01/26 19:59:21
I don't think so!
Lasse Reichstein
2009/01/27 06:54:28
Argh, easily fooled by missing indentation. Ignore
| |
| 1486 } | 1484 } |
| 1487 | 1485 |
| 1488 // Generate deferred actions here along with code to undo them again. | 1486 // Generate deferred actions here along with code to undo them again. |
| 1489 OutSet affected_registers; | 1487 OutSet affected_registers; |
| 1490 int max_register = FindAffectedRegisters(&affected_registers); | 1488 int max_register = FindAffectedRegisters(&affected_registers); |
| 1491 PushAffectedRegisters(assembler, max_register, affected_registers); | 1489 PushAffectedRegisters(assembler, max_register, affected_registers); |
| 1492 PerformDeferredActions(assembler, max_register, affected_registers); | 1490 PerformDeferredActions(assembler, max_register, affected_registers); |
| 1493 if (backtrack() != NULL) { | 1491 if (backtrack() != NULL) { |
| 1494 // Here we have a concrete backtrack location. These are set up by choice | 1492 // Here we have a concrete backtrack location. These are set up by choice |
| 1495 // nodes and so they indicate that we have a deferred save of the current | 1493 // nodes and so they indicate that we have a deferred save of the current |
| 1496 // position which we may need to emit here. | 1494 // position which we may need to emit here. |
| 1497 assembler->PushCurrentPosition(); | 1495 assembler->PushCurrentPosition(); |
| 1498 } | 1496 } |
| 1499 if (cp_offset_ != 0) { | 1497 if (cp_offset_ != 0) { |
| 1500 assembler->AdvanceCurrentPosition(cp_offset_); | 1498 assembler->AdvanceCurrentPosition(cp_offset_); |
| 1501 } | 1499 } |
| 1502 | 1500 |
| 1503 // Create a new trivial state and generate the node with that. | 1501 // Create a new trivial state and generate the node with that. |
| 1504 Label undo; | 1502 Label undo; |
| 1505 assembler->PushBacktrack(&undo); | 1503 assembler->PushBacktrack(&undo); |
| 1506 Trace new_state; | 1504 Trace new_state; |
| 1507 bool ok = successor->Emit(compiler, &new_state); | 1505 successor->Emit(compiler, &new_state); |
| 1508 | 1506 |
| 1509 // On backtrack we need to restore state. | 1507 // On backtrack we need to restore state. |
| 1510 assembler->Bind(&undo); | 1508 assembler->Bind(&undo); |
| 1511 if (!ok) return false; | |
| 1512 if (backtrack() != NULL) { | 1509 if (backtrack() != NULL) { |
| 1513 assembler->PopCurrentPosition(); | 1510 assembler->PopCurrentPosition(); |
| 1514 } | 1511 } |
| 1515 RestoreAffectedRegisters(assembler, max_register, affected_registers); | 1512 RestoreAffectedRegisters(assembler, max_register, affected_registers); |
| 1516 if (backtrack() == NULL) { | 1513 if (backtrack() == NULL) { |
| 1517 assembler->Backtrack(); | 1514 assembler->Backtrack(); |
| 1518 } else { | 1515 } else { |
| 1519 assembler->GoTo(backtrack()); | 1516 assembler->GoTo(backtrack()); |
| 1520 } | 1517 } |
| 1521 | |
| 1522 return true; | |
| 1523 } | 1518 } |
| 1524 | 1519 |
| 1525 | 1520 |
| 1526 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) { | 1521 void NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 1527 if (!trace->is_trivial()) { | 1522 if (!trace->is_trivial()) { |
| 1528 return trace->Flush(compiler, this); | 1523 trace->Flush(compiler, this); |
| 1524 return; | |
| 1529 } | 1525 } |
| 1530 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1526 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1531 if (!label()->is_bound()) { | 1527 if (!label()->is_bound()) { |
| 1532 assembler->Bind(label()); | 1528 assembler->Bind(label()); |
| 1533 } | 1529 } |
| 1534 assembler->ReadCurrentPositionFromRegister(current_position_register_); | 1530 assembler->ReadCurrentPositionFromRegister(current_position_register_); |
| 1535 assembler->ReadStackPointerFromRegister(stack_pointer_register_); | 1531 assembler->ReadStackPointerFromRegister(stack_pointer_register_); |
| 1536 // Now that we have unwound the stack we find at the top of the stack the | 1532 // Now that we have unwound the stack we find at the top of the stack the |
| 1537 // backtrack that the BeginSubmatch node got. | 1533 // backtrack that the BeginSubmatch node got. |
| 1538 assembler->Backtrack(); | 1534 assembler->Backtrack(); |
| 1539 return true; | |
| 1540 } | 1535 } |
| 1541 | 1536 |
| 1542 | 1537 |
| 1543 bool EndNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 1538 void EndNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 1544 if (!trace->is_trivial()) { | 1539 if (!trace->is_trivial()) { |
| 1545 return trace->Flush(compiler, this); | 1540 trace->Flush(compiler, this); |
| 1541 return; | |
| 1546 } | 1542 } |
| 1547 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1543 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1548 if (!label()->is_bound()) { | 1544 if (!label()->is_bound()) { |
| 1549 assembler->Bind(label()); | 1545 assembler->Bind(label()); |
| 1550 } | 1546 } |
| 1551 switch (action_) { | 1547 switch (action_) { |
| 1552 case ACCEPT: | 1548 case ACCEPT: |
| 1553 assembler->Succeed(); | 1549 assembler->Succeed(); |
| 1554 return true; | 1550 return; |
| 1555 case BACKTRACK: | 1551 case BACKTRACK: |
| 1556 assembler->GoTo(trace->backtrack()); | 1552 assembler->GoTo(trace->backtrack()); |
| 1557 return true; | 1553 return; |
| 1558 case NEGATIVE_SUBMATCH_SUCCESS: | 1554 case NEGATIVE_SUBMATCH_SUCCESS: |
| 1559 // This case is handled in a different virtual method. | 1555 // This case is handled in a different virtual method. |
| 1560 UNREACHABLE(); | 1556 UNREACHABLE(); |
| 1561 } | 1557 } |
| 1562 UNIMPLEMENTED(); | 1558 UNIMPLEMENTED(); |
| 1563 return false; | |
| 1564 } | 1559 } |
| 1565 | 1560 |
| 1566 | 1561 |
| 1567 void GuardedAlternative::AddGuard(Guard* guard) { | 1562 void GuardedAlternative::AddGuard(Guard* guard) { |
| 1568 if (guards_ == NULL) | 1563 if (guards_ == NULL) |
| 1569 guards_ = new ZoneList<Guard*>(1); | 1564 guards_ = new ZoneList<Guard*>(1); |
| 1570 guards_->Add(guard); | 1565 guards_->Add(guard); |
| 1571 } | 1566 } |
| 1572 | 1567 |
| 1573 | 1568 |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1950 // non-generic versions we generate so as not to overdo it. | 1945 // non-generic versions we generate so as not to overdo it. |
| 1951 trace_count_++; | 1946 trace_count_++; |
| 1952 if (trace_count_ < kMaxCopiesCodeGenerated && | 1947 if (trace_count_ < kMaxCopiesCodeGenerated && |
| 1953 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { | 1948 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
| 1954 return CONTINUE; | 1949 return CONTINUE; |
| 1955 } | 1950 } |
| 1956 | 1951 |
| 1957 // If we get here code has been generated for this node too many times or | 1952 // If we get here code has been generated for this node too many times or |
| 1958 // recursion is too deep. Time to switch to a generic version. The code for | 1953 // recursion is too deep. Time to switch to a generic version. The code for |
| 1959 // generic versions above can handle deep recursion properly. | 1954 // generic versions above can handle deep recursion properly. |
| 1960 bool ok = trace->Flush(compiler, this); | 1955 trace->Flush(compiler, this); |
| 1961 return ok ? DONE : FAIL; | 1956 return DONE; |
| 1962 } | 1957 } |
| 1963 | 1958 |
| 1964 | 1959 |
| 1965 int ActionNode::EatsAtLeast(int recursion_depth) { | 1960 int ActionNode::EatsAtLeast(int recursion_depth) { |
| 1966 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; | 1961 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; |
| 1967 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! | 1962 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! |
| 1968 return on_success()->EatsAtLeast(recursion_depth + 1); | 1963 return on_success()->EatsAtLeast(recursion_depth + 1); |
| 1969 } | 1964 } |
| 1970 | 1965 |
| 1971 | 1966 |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2367 if (fall_through_on_word) { | 2362 if (fall_through_on_word) { |
| 2368 assembler->CheckNotCharacter('_', non_word); | 2363 assembler->CheckNotCharacter('_', non_word); |
| 2369 } else { | 2364 } else { |
| 2370 assembler->CheckCharacter('_', word); | 2365 assembler->CheckCharacter('_', word); |
| 2371 } | 2366 } |
| 2372 } | 2367 } |
| 2373 | 2368 |
| 2374 | 2369 |
| 2375 // Emit the code to check for a ^ in multiline mode (1-character lookbehind | 2370 // Emit the code to check for a ^ in multiline mode (1-character lookbehind |
| 2376 // that matches newline or the start of input). | 2371 // that matches newline or the start of input). |
| 2377 static bool EmitHat(RegExpCompiler* compiler, | 2372 static void EmitHat(RegExpCompiler* compiler, |
| 2378 RegExpNode* on_success, | 2373 RegExpNode* on_success, |
| 2379 Trace* trace) { | 2374 Trace* trace) { |
| 2380 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2375 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2381 // We will be loading the previous character into the current character | 2376 // We will be loading the previous character into the current character |
| 2382 // register. | 2377 // register. |
| 2383 Trace new_trace(*trace); | 2378 Trace new_trace(*trace); |
| 2384 new_trace.InvalidateCurrentCharacter(); | 2379 new_trace.InvalidateCurrentCharacter(); |
| 2385 | 2380 |
| 2386 Label ok; | 2381 Label ok; |
| 2387 if (new_trace.cp_offset() == 0) { | 2382 if (new_trace.cp_offset() == 0) { |
| 2388 // The start of input counts as a newline in this context, so skip to | 2383 // The start of input counts as a newline in this context, so skip to |
| 2389 // ok if we are at the start. | 2384 // ok if we are at the start. |
| 2390 assembler->CheckAtStart(&ok); | 2385 assembler->CheckAtStart(&ok); |
| 2391 } | 2386 } |
| 2392 // We already checked that we are not at the start of input so it must be | 2387 // We already checked that we are not at the start of input so it must be |
| 2393 // OK to load the previous character. | 2388 // OK to load the previous character. |
| 2394 assembler->LoadCurrentCharacter(new_trace.cp_offset() -1, | 2389 assembler->LoadCurrentCharacter(new_trace.cp_offset() -1, |
| 2395 new_trace.backtrack(), | 2390 new_trace.backtrack(), |
| 2396 false); | 2391 false); |
| 2397 // Newline means \n, \r, 0x2028 or 0x2029. | 2392 // Newline means \n, \r, 0x2028 or 0x2029. |
| 2398 if (!compiler->ascii()) { | 2393 if (!compiler->ascii()) { |
| 2399 assembler->CheckCharacterAfterAnd(0x2028, 0xfffe, &ok); | 2394 assembler->CheckCharacterAfterAnd(0x2028, 0xfffe, &ok); |
| 2400 } | 2395 } |
| 2401 assembler->CheckCharacter('\n', &ok); | 2396 assembler->CheckCharacter('\n', &ok); |
| 2402 assembler->CheckNotCharacter('\r', new_trace.backtrack()); | 2397 assembler->CheckNotCharacter('\r', new_trace.backtrack()); |
| 2403 assembler->Bind(&ok); | 2398 assembler->Bind(&ok); |
| 2404 return on_success->Emit(compiler, &new_trace); | 2399 on_success->Emit(compiler, &new_trace); |
| 2405 } | 2400 } |
| 2406 | 2401 |
| 2407 | 2402 |
| 2408 // Emit the code to handle \b and \B (word-boundary or non-word-boundary). | 2403 // Emit the code to handle \b and \B (word-boundary or non-word-boundary). |
| 2409 static bool EmitBoundaryCheck(AssertionNode::AssertionNodeType type, | 2404 static void EmitBoundaryCheck(AssertionNode::AssertionNodeType type, |
| 2410 RegExpCompiler* compiler, | 2405 RegExpCompiler* compiler, |
| 2411 RegExpNode* on_success, | 2406 RegExpNode* on_success, |
| 2412 Trace* trace) { | 2407 Trace* trace) { |
| 2413 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2408 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2414 Label before_non_word; | 2409 Label before_non_word; |
| 2415 Label before_word; | 2410 Label before_word; |
| 2416 if (trace->characters_preloaded() != 1) { | 2411 if (trace->characters_preloaded() != 1) { |
| 2417 assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word); | 2412 assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word); |
| 2418 } | 2413 } |
| 2419 // Fall through on non-word. | 2414 // Fall through on non-word. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2461 // We already checked that we are not at the start of input so it must be | 2456 // We already checked that we are not at the start of input so it must be |
| 2462 // OK to load the previous character. | 2457 // OK to load the previous character. |
| 2463 assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, | 2458 assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, |
| 2464 &ok, // Unused dummy label in this call. | 2459 &ok, // Unused dummy label in this call. |
| 2465 false); | 2460 false); |
| 2466 bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY); | 2461 bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY); |
| 2467 EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word); | 2462 EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word); |
| 2468 | 2463 |
| 2469 assembler->Bind(&ok); | 2464 assembler->Bind(&ok); |
| 2470 | 2465 |
| 2471 return on_success->Emit(compiler, &new_trace); | 2466 on_success->Emit(compiler, &new_trace); |
| 2472 } | 2467 } |
| 2473 | 2468 |
| 2474 | 2469 |
| 2475 bool AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 2470 void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2476 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2471 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2477 switch (type_) { | 2472 switch (type_) { |
| 2478 case AT_END: { | 2473 case AT_END: { |
| 2479 Label ok; | 2474 Label ok; |
| 2480 assembler->LoadCurrentCharacter(trace->cp_offset(), &ok); | 2475 assembler->LoadCurrentCharacter(trace->cp_offset(), &ok); |
| 2481 assembler->GoTo(trace->backtrack()); | 2476 assembler->GoTo(trace->backtrack()); |
| 2482 assembler->Bind(&ok); | 2477 assembler->Bind(&ok); |
| 2483 break; | 2478 break; |
| 2484 } | 2479 } |
| 2485 case AT_START: | 2480 case AT_START: |
| 2486 assembler->CheckNotAtStart(trace->backtrack()); | 2481 assembler->CheckNotAtStart(trace->backtrack()); |
| 2487 break; | 2482 break; |
| 2488 case AFTER_NEWLINE: | 2483 case AFTER_NEWLINE: |
| 2489 return EmitHat(compiler, on_success(), trace); | 2484 EmitHat(compiler, on_success(), trace); |
| 2485 return; | |
| 2490 case AT_NON_BOUNDARY: | 2486 case AT_NON_BOUNDARY: |
| 2491 case AT_BOUNDARY: | 2487 case AT_BOUNDARY: |
| 2492 return EmitBoundaryCheck(type_, compiler, on_success(), trace); | 2488 EmitBoundaryCheck(type_, compiler, on_success(), trace); |
| 2489 return; | |
| 2493 } | 2490 } |
| 2494 return on_success()->Emit(compiler, trace); | 2491 on_success()->Emit(compiler, trace); |
| 2495 } | 2492 } |
| 2496 | 2493 |
| 2497 | 2494 |
| 2498 // We call this repeatedly to generate code for each pass over the text node. | 2495 // We call this repeatedly to generate code for each pass over the text node. |
| 2499 // The passes are in increasing order of difficulty because we hope one | 2496 // The passes are in increasing order of difficulty because we hope one |
| 2500 // of the first passes will fail in which case we are saved the work of the | 2497 // of the first passes will fail in which case we are saved the work of the |
| 2501 // later passes. for example for the case independent regexp /%[asdfghjkl]a/ | 2498 // later passes. for example for the case independent regexp /%[asdfghjkl]a/ |
| 2502 // we will check the '%' in the first pass, the case independent 'a' in the | 2499 // we will check the '%' in the first pass, the case independent 'a' in the |
| 2503 // second pass and the character class in the last pass. | 2500 // second pass and the character class in the last pass. |
| 2504 // | 2501 // |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2627 } | 2624 } |
| 2628 } | 2625 } |
| 2629 | 2626 |
| 2630 | 2627 |
| 2631 // This generates the code to match a text node. A text node can contain | 2628 // This generates the code to match a text node. A text node can contain |
| 2632 // straight character sequences (possibly to be matched in a case-independent | 2629 // straight character sequences (possibly to be matched in a case-independent |
| 2633 // way) and character classes. For efficiency we do not do this in a single | 2630 // way) and character classes. For efficiency we do not do this in a single |
| 2634 // pass from left to right. Instead we pass over the text node several times, | 2631 // pass from left to right. Instead we pass over the text node several times, |
| 2635 // emitting code for some character positions every time. See the comment on | 2632 // emitting code for some character positions every time. See the comment on |
| 2636 // TextEmitPass for details. | 2633 // TextEmitPass for details. |
| 2637 bool TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 2634 void TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2638 LimitResult limit_result = LimitVersions(compiler, trace); | 2635 LimitResult limit_result = LimitVersions(compiler, trace); |
| 2639 if (limit_result == FAIL) return false; | 2636 if (limit_result == DONE) return; |
| 2640 if (limit_result == DONE) return true; | |
| 2641 ASSERT(limit_result == CONTINUE); | 2637 ASSERT(limit_result == CONTINUE); |
| 2642 | 2638 |
| 2639 if (trace->cp_offset() + Length() > RegExpMacroAssembler::kMaxCPOffset) { | |
| 2640 compiler->SetRegExpTooBig(); | |
| 2641 return; | |
| 2642 } | |
| 2643 | |
| 2643 if (compiler->ascii()) { | 2644 if (compiler->ascii()) { |
| 2644 int dummy = 0; | 2645 int dummy = 0; |
| 2645 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); | 2646 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); |
| 2646 } | 2647 } |
| 2647 | 2648 |
| 2648 bool first_elt_done = false; | 2649 bool first_elt_done = false; |
| 2649 int bound_checked_to = trace->cp_offset() - 1; | 2650 int bound_checked_to = trace->cp_offset() - 1; |
| 2650 bound_checked_to += trace->bound_checked_up_to(); | 2651 bound_checked_to += trace->bound_checked_up_to(); |
| 2651 | 2652 |
| 2652 // If a character is preloaded into the current character register then | 2653 // If a character is preloaded into the current character register then |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2690 &bound_checked_to); | 2691 &bound_checked_to); |
| 2691 } | 2692 } |
| 2692 TextEmitPass(compiler, | 2693 TextEmitPass(compiler, |
| 2693 CHARACTER_CLASS_MATCH, | 2694 CHARACTER_CLASS_MATCH, |
| 2694 false, | 2695 false, |
| 2695 trace, | 2696 trace, |
| 2696 first_elt_done, | 2697 first_elt_done, |
| 2697 &bound_checked_to); | 2698 &bound_checked_to); |
| 2698 | 2699 |
| 2699 Trace successor_trace(*trace); | 2700 Trace successor_trace(*trace); |
| 2700 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler->ascii()); | 2701 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler); |
| 2701 RecursionCheck rc(compiler); | 2702 RecursionCheck rc(compiler); |
| 2702 return on_success()->Emit(compiler, &successor_trace); | 2703 on_success()->Emit(compiler, &successor_trace); |
| 2703 } | 2704 } |
| 2704 | 2705 |
| 2705 | 2706 |
| 2706 void Trace::InvalidateCurrentCharacter() { | 2707 void Trace::InvalidateCurrentCharacter() { |
| 2707 characters_preloaded_ = 0; | 2708 characters_preloaded_ = 0; |
| 2708 } | 2709 } |
| 2709 | 2710 |
| 2710 | 2711 |
| 2711 void Trace::AdvanceCurrentPositionInTrace(int by, bool ascii) { | 2712 void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) { |
| 2712 ASSERT(by > 0); | 2713 ASSERT(by > 0); |
| 2713 // We don't have an instruction for shifting the current character register | 2714 // We don't have an instruction for shifting the current character register |
| 2714 // down or for using a shifted value for anything so lets just forget that | 2715 // down or for using a shifted value for anything so lets just forget that |
| 2715 // we preloaded any characters into it. | 2716 // we preloaded any characters into it. |
| 2716 characters_preloaded_ = 0; | 2717 characters_preloaded_ = 0; |
| 2717 // Adjust the offsets of the quick check performed information. This | 2718 // Adjust the offsets of the quick check performed information. This |
| 2718 // information is used to find out what we already determined about the | 2719 // information is used to find out what we already determined about the |
| 2719 // characters by means of mask and compare. | 2720 // characters by means of mask and compare. |
| 2720 quick_check_performed_.Advance(by, ascii); | 2721 quick_check_performed_.Advance(by, compiler->ascii()); |
| 2721 cp_offset_ += by; | 2722 cp_offset_ += by; |
| 2723 if (cp_offset_ > RegExpMacroAssembler::kMaxCPOffset) { | |
| 2724 compiler->SetRegExpTooBig(); | |
| 2725 cp_offset_ = 0; | |
| 2726 } | |
| 2722 bound_checked_up_to_ = Max(0, bound_checked_up_to_ - by); | 2727 bound_checked_up_to_ = Max(0, bound_checked_up_to_ - by); |
| 2723 } | 2728 } |
| 2724 | 2729 |
| 2725 | 2730 |
| 2726 void TextNode::MakeCaseIndependent() { | 2731 void TextNode::MakeCaseIndependent() { |
| 2727 int element_count = elms_->length(); | 2732 int element_count = elms_->length(); |
| 2728 for (int i = 0; i < element_count; i++) { | 2733 for (int i = 0; i < element_count; i++) { |
| 2729 TextElement elm = elms_->at(i); | 2734 TextElement elm = elms_->at(i); |
| 2730 if (elm.type == TextElement::CHAR_CLASS) { | 2735 if (elm.type == TextElement::CHAR_CLASS) { |
| 2731 RegExpCharacterClass* cc = elm.data.u_char_class; | 2736 RegExpCharacterClass* cc = elm.data.u_char_class; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2782 } | 2787 } |
| 2783 | 2788 |
| 2784 | 2789 |
| 2785 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { | 2790 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { |
| 2786 ASSERT_EQ(continue_node_, NULL); | 2791 ASSERT_EQ(continue_node_, NULL); |
| 2787 AddAlternative(alt); | 2792 AddAlternative(alt); |
| 2788 continue_node_ = alt.node(); | 2793 continue_node_ = alt.node(); |
| 2789 } | 2794 } |
| 2790 | 2795 |
| 2791 | 2796 |
| 2792 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 2797 void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2793 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2798 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2794 if (trace->stop_node() == this) { | 2799 if (trace->stop_node() == this) { |
| 2795 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2800 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2796 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); | 2801 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); |
| 2797 // Update the counter-based backtracking info on the stack. This is an | 2802 // Update the counter-based backtracking info on the stack. This is an |
| 2798 // optimization for greedy loops (see below). | 2803 // optimization for greedy loops (see below). |
| 2799 ASSERT(trace->cp_offset() == text_length); | 2804 ASSERT(trace->cp_offset() == text_length); |
| 2800 macro_assembler->AdvanceCurrentPosition(text_length); | 2805 macro_assembler->AdvanceCurrentPosition(text_length); |
| 2801 macro_assembler->GoTo(trace->loop_label()); | 2806 macro_assembler->GoTo(trace->loop_label()); |
| 2802 return true; | 2807 return; |
| 2803 } | 2808 } |
| 2804 ASSERT(trace->stop_node() == NULL); | 2809 ASSERT(trace->stop_node() == NULL); |
| 2805 if (!trace->is_trivial()) { | 2810 if (!trace->is_trivial()) { |
| 2806 return trace->Flush(compiler, this); | 2811 trace->Flush(compiler, this); |
| 2812 return; | |
| 2807 } | 2813 } |
| 2808 return ChoiceNode::Emit(compiler, trace); | 2814 ChoiceNode::Emit(compiler, trace); |
| 2809 } | 2815 } |
| 2810 | 2816 |
| 2811 | 2817 |
| 2812 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { | 2818 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { |
| 2813 int preload_characters = EatsAtLeast(0); | 2819 int preload_characters = EatsAtLeast(0); |
| 2814 #ifdef CAN_READ_UNALIGNED | 2820 #ifdef CAN_READ_UNALIGNED |
| 2815 bool ascii = compiler->ascii(); | 2821 bool ascii = compiler->ascii(); |
| 2816 if (ascii) { | 2822 if (ascii) { |
| 2817 if (preload_characters > 4) preload_characters = 4; | 2823 if (preload_characters > 4) preload_characters = 4; |
| 2818 // We can't preload 3 characters because there is no machine instruction | 2824 // 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... | |
| 2951 * | / | | 2957 * | / | |
| 2952 * | R | | 2958 * | R | |
| 2953 * | / | | 2959 * | / | |
| 2954 * F VL | | 2960 * F VL | |
| 2955 * <------U | | 2961 * <------U | |
| 2956 * back |S | | 2962 * back |S | |
| 2957 * \______________/ | 2963 * \______________/ |
| 2958 */ | 2964 */ |
| 2959 | 2965 |
| 2960 | 2966 |
| 2961 bool ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 2967 void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 2962 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2968 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 2963 int choice_count = alternatives_->length(); | 2969 int choice_count = alternatives_->length(); |
| 2964 #ifdef DEBUG | 2970 #ifdef DEBUG |
| 2965 for (int i = 0; i < choice_count - 1; i++) { | 2971 for (int i = 0; i < choice_count - 1; i++) { |
| 2966 GuardedAlternative alternative = alternatives_->at(i); | 2972 GuardedAlternative alternative = alternatives_->at(i); |
| 2967 ZoneList<Guard*>* guards = alternative.guards(); | 2973 ZoneList<Guard*>* guards = alternative.guards(); |
| 2968 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2974 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 2969 for (int j = 0; j < guard_count; j++) { | 2975 for (int j = 0; j < guard_count; j++) { |
| 2970 ASSERT(!trace->mentions_reg(guards->at(j)->reg())); | 2976 ASSERT(!trace->mentions_reg(guards->at(j)->reg())); |
| 2971 } | 2977 } |
| 2972 } | 2978 } |
| 2973 #endif | 2979 #endif |
| 2974 | 2980 |
| 2975 LimitResult limit_result = LimitVersions(compiler, trace); | 2981 LimitResult limit_result = LimitVersions(compiler, trace); |
| 2976 if (limit_result == DONE) return true; | 2982 if (limit_result == DONE) return; |
| 2977 if (limit_result == FAIL) return false; | |
| 2978 ASSERT(limit_result == CONTINUE); | 2983 ASSERT(limit_result == CONTINUE); |
| 2979 | 2984 |
| 2980 RecursionCheck rc(compiler); | 2985 RecursionCheck rc(compiler); |
| 2981 | 2986 |
| 2982 Trace* current_trace = trace; | 2987 Trace* current_trace = trace; |
| 2983 | 2988 |
| 2984 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2989 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
| 2985 bool greedy_loop = false; | 2990 bool greedy_loop = false; |
| 2986 Label greedy_loop_label; | 2991 Label greedy_loop_label; |
| 2987 Trace counter_backtrack_trace; | 2992 Trace counter_backtrack_trace; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2998 ASSERT(trace->stop_node() == NULL); | 3003 ASSERT(trace->stop_node() == NULL); |
| 2999 macro_assembler->PushCurrentPosition(); | 3004 macro_assembler->PushCurrentPosition(); |
| 3000 current_trace = &counter_backtrack_trace; | 3005 current_trace = &counter_backtrack_trace; |
| 3001 Label greedy_match_failed; | 3006 Label greedy_match_failed; |
| 3002 Trace greedy_match_trace; | 3007 Trace greedy_match_trace; |
| 3003 greedy_match_trace.set_backtrack(&greedy_match_failed); | 3008 greedy_match_trace.set_backtrack(&greedy_match_failed); |
| 3004 Label loop_label; | 3009 Label loop_label; |
| 3005 macro_assembler->Bind(&loop_label); | 3010 macro_assembler->Bind(&loop_label); |
| 3006 greedy_match_trace.set_stop_node(this); | 3011 greedy_match_trace.set_stop_node(this); |
| 3007 greedy_match_trace.set_loop_label(&loop_label); | 3012 greedy_match_trace.set_loop_label(&loop_label); |
| 3008 bool ok = alternatives_->at(0).node()->Emit(compiler, | 3013 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace); |
| 3009 &greedy_match_trace); | |
| 3010 macro_assembler->Bind(&greedy_match_failed); | 3014 macro_assembler->Bind(&greedy_match_failed); |
| 3011 if (!ok) { | |
| 3012 greedy_loop_label.Unuse(); | |
| 3013 return false; | |
| 3014 } | |
| 3015 } | 3015 } |
| 3016 | 3016 |
| 3017 Label second_choice; // For use in greedy matches. | 3017 Label second_choice; // For use in greedy matches. |
| 3018 macro_assembler->Bind(&second_choice); | 3018 macro_assembler->Bind(&second_choice); |
| 3019 | 3019 |
| 3020 int first_normal_choice = greedy_loop ? 1 : 0; | 3020 int first_normal_choice = greedy_loop ? 1 : 0; |
| 3021 | 3021 |
| 3022 int preload_characters = CalculatePreloadCharacters(compiler); | 3022 int preload_characters = CalculatePreloadCharacters(compiler); |
| 3023 bool preload_is_current = | 3023 bool preload_is_current = |
| 3024 (current_trace->characters_preloaded() == preload_characters); | 3024 (current_trace->characters_preloaded() == preload_characters); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3076 } | 3076 } |
| 3077 if (i < choice_count - 1) { | 3077 if (i < choice_count - 1) { |
| 3078 new_trace.set_backtrack(&alt_gen->after); | 3078 new_trace.set_backtrack(&alt_gen->after); |
| 3079 } | 3079 } |
| 3080 generate_full_check_inline = true; | 3080 generate_full_check_inline = true; |
| 3081 } | 3081 } |
| 3082 if (generate_full_check_inline) { | 3082 if (generate_full_check_inline) { |
| 3083 for (int j = 0; j < guard_count; j++) { | 3083 for (int j = 0; j < guard_count; j++) { |
| 3084 GenerateGuard(macro_assembler, guards->at(j), &new_trace); | 3084 GenerateGuard(macro_assembler, guards->at(j), &new_trace); |
| 3085 } | 3085 } |
| 3086 if (!alternative.node()->Emit(compiler, &new_trace)) { | 3086 alternative.node()->Emit(compiler, &new_trace); |
| 3087 greedy_loop_label.Unuse(); | |
| 3088 return false; | |
| 3089 } | |
| 3090 preload_is_current = false; | 3087 preload_is_current = false; |
| 3091 } | 3088 } |
| 3092 macro_assembler->Bind(&alt_gen->after); | 3089 macro_assembler->Bind(&alt_gen->after); |
| 3093 } | 3090 } |
| 3094 if (greedy_loop) { | 3091 if (greedy_loop) { |
| 3095 macro_assembler->Bind(&greedy_loop_label); | 3092 macro_assembler->Bind(&greedy_loop_label); |
| 3096 // If we have unwound to the bottom then backtrack. | 3093 // If we have unwound to the bottom then backtrack. |
| 3097 macro_assembler->CheckGreedyLoop(trace->backtrack()); | 3094 macro_assembler->CheckGreedyLoop(trace->backtrack()); |
| 3098 // Otherwise try the second priority at an earlier position. | 3095 // Otherwise try the second priority at an earlier position. |
| 3099 macro_assembler->AdvanceCurrentPosition(-text_length); | 3096 macro_assembler->AdvanceCurrentPosition(-text_length); |
| 3100 macro_assembler->GoTo(&second_choice); | 3097 macro_assembler->GoTo(&second_choice); |
| 3101 } | 3098 } |
| 3102 // At this point we need to generate slow checks for the alternatives where | 3099 // At this point we need to generate slow checks for the alternatives where |
| 3103 // the quick check was inlined. We can recognize these because the associated | 3100 // the quick check was inlined. We can recognize these because the associated |
| 3104 // label was bound. | 3101 // label was bound. |
| 3105 for (int i = first_normal_choice; i < choice_count - 1; i++) { | 3102 for (int i = first_normal_choice; i < choice_count - 1; i++) { |
| 3106 AlternativeGeneration* alt_gen = alt_gens.at(i); | 3103 AlternativeGeneration* alt_gen = alt_gens.at(i); |
| 3107 if (!EmitOutOfLineContinuation(compiler, | 3104 EmitOutOfLineContinuation(compiler, |
| 3108 current_trace, | 3105 current_trace, |
| 3109 alternatives_->at(i), | 3106 alternatives_->at(i), |
| 3110 alt_gen, | 3107 alt_gen, |
| 3111 preload_characters, | 3108 preload_characters, |
| 3112 alt_gens.at(i + 1)->expects_preload)) { | 3109 alt_gens.at(i + 1)->expects_preload); |
| 3113 return false; | |
| 3114 } | |
| 3115 } | 3110 } |
| 3116 return true; | |
| 3117 } | 3111 } |
| 3118 | 3112 |
| 3119 | 3113 |
| 3120 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, | 3114 void ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, |
| 3121 Trace* trace, | 3115 Trace* trace, |
| 3122 GuardedAlternative alternative, | 3116 GuardedAlternative alternative, |
| 3123 AlternativeGeneration* alt_gen, | 3117 AlternativeGeneration* alt_gen, |
| 3124 int preload_characters, | 3118 int preload_characters, |
| 3125 bool next_expects_preload) { | 3119 bool next_expects_preload) { |
| 3126 if (!alt_gen->possible_success.is_linked()) return true; | 3120 if (!alt_gen->possible_success.is_linked()) return; |
| 3127 | 3121 |
| 3128 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 3122 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 3129 macro_assembler->Bind(&alt_gen->possible_success); | 3123 macro_assembler->Bind(&alt_gen->possible_success); |
| 3130 Trace out_of_line_trace(*trace); | 3124 Trace out_of_line_trace(*trace); |
| 3131 out_of_line_trace.set_characters_preloaded(preload_characters); | 3125 out_of_line_trace.set_characters_preloaded(preload_characters); |
| 3132 out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details); | 3126 out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details); |
| 3133 ZoneList<Guard*>* guards = alternative.guards(); | 3127 ZoneList<Guard*>* guards = alternative.guards(); |
| 3134 int guard_count = (guards == NULL) ? 0 : guards->length(); | 3128 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 3135 if (next_expects_preload) { | 3129 if (next_expects_preload) { |
| 3136 Label reload_current_char; | 3130 Label reload_current_char; |
| 3137 out_of_line_trace.set_backtrack(&reload_current_char); | 3131 out_of_line_trace.set_backtrack(&reload_current_char); |
| 3138 for (int j = 0; j < guard_count; j++) { | 3132 for (int j = 0; j < guard_count; j++) { |
| 3139 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); | 3133 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
| 3140 } | 3134 } |
| 3141 bool ok = alternative.node()->Emit(compiler, &out_of_line_trace); | 3135 alternative.node()->Emit(compiler, &out_of_line_trace); |
| 3142 macro_assembler->Bind(&reload_current_char); | 3136 macro_assembler->Bind(&reload_current_char); |
| 3143 // Reload the current character, since the next quick check expects that. | 3137 // Reload the current character, since the next quick check expects that. |
| 3144 // We don't need to check bounds here because we only get into this | 3138 // We don't need to check bounds here because we only get into this |
| 3145 // code through a quick check which already did the checked load. | 3139 // code through a quick check which already did the checked load. |
| 3146 macro_assembler->LoadCurrentCharacter(trace->cp_offset(), | 3140 macro_assembler->LoadCurrentCharacter(trace->cp_offset(), |
| 3147 NULL, | 3141 NULL, |
| 3148 false, | 3142 false, |
| 3149 preload_characters); | 3143 preload_characters); |
| 3150 macro_assembler->GoTo(&(alt_gen->after)); | 3144 macro_assembler->GoTo(&(alt_gen->after)); |
| 3151 return ok; | |
| 3152 } else { | 3145 } else { |
| 3153 out_of_line_trace.set_backtrack(&(alt_gen->after)); | 3146 out_of_line_trace.set_backtrack(&(alt_gen->after)); |
| 3154 for (int j = 0; j < guard_count; j++) { | 3147 for (int j = 0; j < guard_count; j++) { |
| 3155 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); | 3148 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
| 3156 } | 3149 } |
| 3157 return alternative.node()->Emit(compiler, &out_of_line_trace); | 3150 alternative.node()->Emit(compiler, &out_of_line_trace); |
| 3158 } | 3151 } |
| 3159 } | 3152 } |
| 3160 | 3153 |
| 3161 | 3154 |
| 3162 bool ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 3155 void ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 3163 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3156 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 3164 LimitResult limit_result = LimitVersions(compiler, trace); | 3157 LimitResult limit_result = LimitVersions(compiler, trace); |
| 3165 if (limit_result == DONE) return true; | 3158 if (limit_result == DONE) return; |
| 3166 if (limit_result == FAIL) return false; | |
| 3167 ASSERT(limit_result == CONTINUE); | 3159 ASSERT(limit_result == CONTINUE); |
| 3168 | 3160 |
| 3169 RecursionCheck rc(compiler); | 3161 RecursionCheck rc(compiler); |
| 3170 | 3162 |
| 3171 switch (type_) { | 3163 switch (type_) { |
| 3172 case STORE_POSITION: { | 3164 case STORE_POSITION: { |
| 3173 Trace::DeferredCapture | 3165 Trace::DeferredCapture |
| 3174 new_capture(data_.u_position_register.reg, trace); | 3166 new_capture(data_.u_position_register.reg, trace); |
| 3175 Trace new_trace = *trace; | 3167 Trace new_trace = *trace; |
| 3176 new_trace.add_action(&new_capture); | 3168 new_trace.add_action(&new_capture); |
| 3177 return on_success()->Emit(compiler, &new_trace); | 3169 on_success()->Emit(compiler, &new_trace); |
| 3170 break; | |
| 3178 } | 3171 } |
| 3179 case INCREMENT_REGISTER: { | 3172 case INCREMENT_REGISTER: { |
| 3180 Trace::DeferredIncrementRegister | 3173 Trace::DeferredIncrementRegister |
| 3181 new_increment(data_.u_increment_register.reg); | 3174 new_increment(data_.u_increment_register.reg); |
| 3182 Trace new_trace = *trace; | 3175 Trace new_trace = *trace; |
| 3183 new_trace.add_action(&new_increment); | 3176 new_trace.add_action(&new_increment); |
| 3184 return on_success()->Emit(compiler, &new_trace); | 3177 on_success()->Emit(compiler, &new_trace); |
| 3178 break; | |
| 3185 } | 3179 } |
| 3186 case SET_REGISTER: { | 3180 case SET_REGISTER: { |
| 3187 Trace::DeferredSetRegister | 3181 Trace::DeferredSetRegister |
| 3188 new_set(data_.u_store_register.reg, data_.u_store_register.value); | 3182 new_set(data_.u_store_register.reg, data_.u_store_register.value); |
| 3189 Trace new_trace = *trace; | 3183 Trace new_trace = *trace; |
| 3190 new_trace.add_action(&new_set); | 3184 new_trace.add_action(&new_set); |
| 3191 return on_success()->Emit(compiler, &new_trace); | 3185 on_success()->Emit(compiler, &new_trace); |
| 3186 break; | |
| 3192 } | 3187 } |
| 3193 case CLEAR_CAPTURES: { | 3188 case CLEAR_CAPTURES: { |
| 3194 Trace::DeferredClearCaptures | 3189 Trace::DeferredClearCaptures |
| 3195 new_capture(Interval(data_.u_clear_captures.range_from, | 3190 new_capture(Interval(data_.u_clear_captures.range_from, |
| 3196 data_.u_clear_captures.range_to)); | 3191 data_.u_clear_captures.range_to)); |
| 3197 Trace new_trace = *trace; | 3192 Trace new_trace = *trace; |
| 3198 new_trace.add_action(&new_capture); | 3193 new_trace.add_action(&new_capture); |
| 3199 return on_success()->Emit(compiler, &new_trace); | 3194 on_success()->Emit(compiler, &new_trace); |
| 3195 break; | |
| 3200 } | 3196 } |
| 3201 case BEGIN_SUBMATCH: | 3197 case BEGIN_SUBMATCH: |
| 3202 if (!trace->is_trivial()) return trace->Flush(compiler, this); | 3198 if (!trace->is_trivial()) { |
| 3203 assembler->WriteCurrentPositionToRegister( | 3199 trace->Flush(compiler, this); |
| 3204 data_.u_submatch.current_position_register, 0); | 3200 } else { |
| 3205 assembler->WriteStackPointerToRegister( | 3201 assembler->WriteCurrentPositionToRegister( |
| 3206 data_.u_submatch.stack_pointer_register); | 3202 data_.u_submatch.current_position_register, 0); |
| 3207 return on_success()->Emit(compiler, trace); | 3203 assembler->WriteStackPointerToRegister( |
| 3204 data_.u_submatch.stack_pointer_register); | |
| 3205 on_success()->Emit(compiler, trace); | |
| 3206 } | |
| 3207 break; | |
| 3208 case EMPTY_MATCH_CHECK: { | 3208 case EMPTY_MATCH_CHECK: { |
| 3209 int start_pos_reg = data_.u_empty_match_check.start_register; | 3209 int start_pos_reg = data_.u_empty_match_check.start_register; |
| 3210 int stored_pos = 0; | 3210 int stored_pos = 0; |
| 3211 int rep_reg = data_.u_empty_match_check.repetition_register; | 3211 int rep_reg = data_.u_empty_match_check.repetition_register; |
| 3212 bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister); | 3212 bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister); |
| 3213 bool know_dist = trace->GetStoredPosition(start_pos_reg, &stored_pos); | 3213 bool know_dist = trace->GetStoredPosition(start_pos_reg, &stored_pos); |
| 3214 if (know_dist && !has_minimum && stored_pos == trace->cp_offset()) { | 3214 if (know_dist && !has_minimum && stored_pos == trace->cp_offset()) { |
| 3215 // If we know we haven't advanced and there is no minimum we | 3215 // If we know we haven't advanced and there is no minimum we |
| 3216 // can just backtrack immediately. | 3216 // can just backtrack immediately. |
| 3217 assembler->GoTo(trace->backtrack()); | 3217 assembler->GoTo(trace->backtrack()); |
| 3218 return true; | |
| 3219 } else if (know_dist && stored_pos < trace->cp_offset()) { | 3218 } else if (know_dist && stored_pos < trace->cp_offset()) { |
| 3220 // If we know we've advanced we can generate the continuation | 3219 // If we know we've advanced we can generate the continuation |
| 3221 // immediately. | 3220 // immediately. |
| 3222 return on_success()->Emit(compiler, trace); | 3221 on_success()->Emit(compiler, trace); |
| 3222 } else if (!trace->is_trivial()) { | |
| 3223 trace->Flush(compiler, this); | |
| 3224 } else { | |
| 3225 Label skip_empty_check; | |
| 3226 // If we have a minimum number of repetitions we check the current | |
| 3227 // number first and skip the empty check if it's not enough. | |
| 3228 if (has_minimum) { | |
| 3229 int limit = data_.u_empty_match_check.repetition_limit; | |
| 3230 assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check); | |
| 3231 } | |
| 3232 // If the match is empty we bail out, otherwise we fall through | |
| 3233 // to the on-success continuation. | |
| 3234 assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register, | |
| 3235 trace->backtrack()); | |
| 3236 assembler->Bind(&skip_empty_check); | |
| 3237 on_success()->Emit(compiler, trace); | |
| 3223 } | 3238 } |
| 3224 if (!trace->is_trivial()) return trace->Flush(compiler, this); | 3239 break; |
| 3225 Label skip_empty_check; | |
| 3226 // If we have a minimum number of repetitions we check the current | |
| 3227 // number first and skip the empty check if it's not enough. | |
| 3228 if (has_minimum) { | |
| 3229 int limit = data_.u_empty_match_check.repetition_limit; | |
| 3230 assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check); | |
| 3231 } | |
| 3232 // If the match is empty we bail out, otherwise we fall through | |
| 3233 // to the on-success continuation. | |
| 3234 assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register, | |
| 3235 trace->backtrack()); | |
| 3236 assembler->Bind(&skip_empty_check); | |
| 3237 return on_success()->Emit(compiler, trace); | |
| 3238 } | 3240 } |
| 3239 case POSITIVE_SUBMATCH_SUCCESS: | 3241 case POSITIVE_SUBMATCH_SUCCESS: |
| 3240 if (!trace->is_trivial()) return trace->Flush(compiler, this); | 3242 if (!trace->is_trivial()) { |
| 3241 assembler->ReadCurrentPositionFromRegister( | 3243 trace->Flush(compiler, this); |
| 3242 data_.u_submatch.current_position_register); | 3244 } else { |
| 3243 assembler->ReadStackPointerFromRegister( | 3245 assembler->ReadCurrentPositionFromRegister( |
| 3244 data_.u_submatch.stack_pointer_register); | 3246 data_.u_submatch.current_position_register); |
| 3245 return on_success()->Emit(compiler, trace); | 3247 assembler->ReadStackPointerFromRegister( |
| 3248 data_.u_submatch.stack_pointer_register); | |
| 3249 on_success()->Emit(compiler, trace); | |
| 3250 } | |
| 3251 break; | |
| 3246 default: | 3252 default: |
| 3247 UNREACHABLE(); | 3253 UNREACHABLE(); |
| 3248 return false; | |
| 3249 } | 3254 } |
| 3250 } | 3255 } |
| 3251 | 3256 |
| 3252 | 3257 |
| 3253 bool BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 3258 void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 3254 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3259 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 3255 if (!trace->is_trivial()) { | 3260 if (!trace->is_trivial()) { |
| 3256 return trace->Flush(compiler, this); | 3261 trace->Flush(compiler, this); |
| 3262 return; | |
| 3257 } | 3263 } |
| 3258 | 3264 |
| 3259 LimitResult limit_result = LimitVersions(compiler, trace); | 3265 LimitResult limit_result = LimitVersions(compiler, trace); |
| 3260 if (limit_result == DONE) return true; | 3266 if (limit_result == DONE) return; |
| 3261 if (limit_result == FAIL) return false; | |
| 3262 ASSERT(limit_result == CONTINUE); | 3267 ASSERT(limit_result == CONTINUE); |
| 3263 | 3268 |
| 3264 RecursionCheck rc(compiler); | 3269 RecursionCheck rc(compiler); |
| 3265 | 3270 |
| 3266 ASSERT_EQ(start_reg_ + 1, end_reg_); | 3271 ASSERT_EQ(start_reg_ + 1, end_reg_); |
| 3267 if (compiler->ignore_case()) { | 3272 if (compiler->ignore_case()) { |
| 3268 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, | 3273 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, |
| 3269 trace->backtrack()); | 3274 trace->backtrack()); |
| 3270 } else { | 3275 } else { |
| 3271 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); | 3276 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); |
| 3272 } | 3277 } |
| 3273 return on_success()->Emit(compiler, trace); | 3278 on_success()->Emit(compiler, trace); |
| 3274 } | 3279 } |
| 3275 | 3280 |
| 3276 | 3281 |
| 3277 // ------------------------------------------------------------------- | 3282 // ------------------------------------------------------------------- |
| 3278 // Dot/dotty output | 3283 // Dot/dotty output |
| 3279 | 3284 |
| 3280 | 3285 |
| 3281 #ifdef DEBUG | 3286 #ifdef DEBUG |
| 3282 | 3287 |
| 3283 | 3288 |
| (...skipping 1347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4631 RegExpNode* target = that->on_success(); | 4636 RegExpNode* target = that->on_success(); |
| 4632 target->Accept(this); | 4637 target->Accept(this); |
| 4633 } | 4638 } |
| 4634 | 4639 |
| 4635 | 4640 |
| 4636 Handle<FixedArray> RegExpEngine::Compile(RegExpCompileData* data, | 4641 Handle<FixedArray> RegExpEngine::Compile(RegExpCompileData* data, |
| 4637 bool ignore_case, | 4642 bool ignore_case, |
| 4638 bool is_multiline, | 4643 bool is_multiline, |
| 4639 Handle<String> pattern, | 4644 Handle<String> pattern, |
| 4640 bool is_ascii) { | 4645 bool is_ascii) { |
| 4646 if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) { | |
| 4647 return IrregexpRegExpTooBig(pattern); | |
| 4648 } | |
| 4641 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); | 4649 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); |
| 4642 // Wrap the body of the regexp in capture #0. | 4650 // Wrap the body of the regexp in capture #0. |
| 4643 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, | 4651 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, |
| 4644 0, | 4652 0, |
| 4645 &compiler, | 4653 &compiler, |
| 4646 compiler.accept()); | 4654 compiler.accept()); |
| 4647 RegExpNode* node = captured_body; | 4655 RegExpNode* node = captured_body; |
| 4648 if (!data->tree->IsAnchored()) { | 4656 if (!data->tree->IsAnchored()) { |
| 4649 // Add a .*? at the beginning, outside the body capture, unless | 4657 // Add a .*? at the beginning, outside the body capture, unless |
| 4650 // this expression is anchored at the beginning. | 4658 // this expression is anchored at the beginning. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4682 EmbeddedVector<byte, 1024> codes; | 4690 EmbeddedVector<byte, 1024> codes; |
| 4683 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4691 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 4684 return compiler.Assemble(¯o_assembler, | 4692 return compiler.Assemble(¯o_assembler, |
| 4685 node, | 4693 node, |
| 4686 data->capture_count, | 4694 data->capture_count, |
| 4687 pattern); | 4695 pattern); |
| 4688 } | 4696 } |
| 4689 | 4697 |
| 4690 | 4698 |
| 4691 }} // namespace v8::internal | 4699 }} // namespace v8::internal |
| OLD | NEW |