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 |