Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: src/jsregexp.cc

Issue 18587: Eliminate the code that handles fallback to JSCRE. The only way to get... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
4682 EmbeddedVector<byte, 1024> codes; 4690 EmbeddedVector<byte, 1024> codes;
4683 RegExpMacroAssemblerIrregexp macro_assembler(codes); 4691 RegExpMacroAssemblerIrregexp macro_assembler(codes);
4684 return compiler.Assemble(&macro_assembler, 4692 return compiler.Assemble(&macro_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
OLDNEW
« no previous file with comments | « src/jsregexp.h ('k') | src/regexp-macro-assembler.h » ('j') | src/regexp-macro-assembler.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698