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

Side by Side Diff: src/jsregexp.cc

Issue 17378: Capture register clearing on loop iteration (Closed)
Patch Set: Created 11 years, 11 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
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 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after
1297 array->set(RegExpImpl::kIrregexpCodeIndex, *code); 1297 array->set(RegExpImpl::kIrregexpCodeIndex, *code);
1298 work_list_ = NULL; 1298 work_list_ = NULL;
1299 #ifdef DEBUG 1299 #ifdef DEBUG
1300 if (FLAG_trace_regexp_assembler) { 1300 if (FLAG_trace_regexp_assembler) {
1301 delete macro_assembler_; 1301 delete macro_assembler_;
1302 } 1302 }
1303 #endif 1303 #endif
1304 return array; 1304 return array;
1305 } 1305 }
1306 1306
1307 bool GenerationVariant::DeferredAction::Mentions(int that) {
1308 if (type() == ActionNode::CLEAR_CAPTURES) {
1309 Interval range = static_cast<DeferredClearCaptures*>(this)->range();
1310 return range.Contains(that);
1311 } else {
1312 return reg() == that;
1313 }
1314 }
1315
1307 1316
1308 bool GenerationVariant::mentions_reg(int reg) { 1317 bool GenerationVariant::mentions_reg(int reg) {
1309 for (DeferredAction* action = actions_; 1318 for (DeferredAction* action = actions_;
1310 action != NULL; 1319 action != NULL;
1311 action = action->next()) { 1320 action = action->next()) {
1312 if (reg == action->reg()) return true; 1321 if (action->Mentions(reg))
1322 return true;
1313 } 1323 }
1314 return false; 1324 return false;
1315 } 1325 }
1316 1326
1317 1327
1318 bool GenerationVariant::GetStoredPosition(int reg, int* cp_offset) { 1328 bool GenerationVariant::GetStoredPosition(int reg, int* cp_offset) {
1319 ASSERT_EQ(0, *cp_offset); 1329 ASSERT_EQ(0, *cp_offset);
1320 for (DeferredAction* action = actions_; 1330 for (DeferredAction* action = actions_;
1321 action != NULL; 1331 action != NULL;
1322 action = action->next()) { 1332 action = action->next()) {
1323 if (reg == action->reg()) { 1333 if (action->Mentions(reg)) {
1324 if (action->type() == ActionNode::STORE_POSITION) { 1334 if (action->type() == ActionNode::STORE_POSITION) {
1325 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); 1335 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset();
1326 return true; 1336 return true;
1327 } else { 1337 } else {
1328 return false; 1338 return false;
1329 } 1339 }
1330 } 1340 }
1331 } 1341 }
1332 return false; 1342 return false;
1333 } 1343 }
1334 1344
1335 1345
1336 int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) { 1346 int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) {
1337 int max_register = RegExpCompiler::kNoRegister; 1347 int max_register = RegExpCompiler::kNoRegister;
1338 for (DeferredAction* action = actions_; 1348 for (DeferredAction* action = actions_;
1339 action != NULL; 1349 action != NULL;
1340 action = action->next()) { 1350 action = action->next()) {
1341 affected_registers->Set(action->reg()); 1351 if (action->type() == ActionNode::CLEAR_CAPTURES) {
1342 if (action->reg() > max_register) max_register = action->reg(); 1352 Interval range = static_cast<DeferredClearCaptures*>(action)->range();
1353 for (int i = range.from(); i < range.to(); i++)
1354 affected_registers->Set(i);
1355 if (range.to() > max_register) max_register = range.to();
1356 } else {
1357 affected_registers->Set(action->reg());
1358 if (action->reg() > max_register) max_register = action->reg();
1359 }
1343 } 1360 }
1344 return max_register; 1361 return max_register;
1345 } 1362 }
1346 1363
1347 1364
1348 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler, 1365 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler,
1349 int max_register, 1366 int max_register,
1350 OutSet& affected_registers) { 1367 OutSet& affected_registers) {
1351 // Stay safe and check every half times the limit. 1368 // Stay safe and check every half times the limit.
1352 // (Round up in case the limit is 1). 1369 // (Round up in case the limit is 1).
1353 int push_limit = (assembler->stack_limit_slack() + 1) / 2; 1370 int push_limit = (assembler->stack_limit_slack() + 1) / 2;
1354 for (int reg = 0, pushes = 0; reg <= max_register; reg++) { 1371 for (int reg = 0, pushes = 0; reg <= max_register; reg++) {
1355 if (affected_registers.Get(reg)) { 1372 if (affected_registers.Get(reg)) {
1356 pushes++; 1373 pushes++;
1357 RegExpMacroAssembler::StackCheckFlag check_stack_limit = 1374 RegExpMacroAssembler::StackCheckFlag check_stack_limit =
1358 (pushes % push_limit) == 0 ? 1375 (pushes % push_limit) == 0 ?
1359 RegExpMacroAssembler::kCheckStackLimit : 1376 RegExpMacroAssembler::kCheckStackLimit :
1360 RegExpMacroAssembler::kNoStackLimitCheck; 1377 RegExpMacroAssembler::kNoStackLimitCheck;
1361 assembler->PushRegister(reg, check_stack_limit); 1378 assembler->PushRegister(reg, check_stack_limit);
Erik Corry 2009/01/14 09:24:31 It's a waste to push...
Christian Plesner Hansen 2009/01/14 11:31:35 I'd like to defer that optimization.
1362 } 1379 }
1363 } 1380 }
1364 } 1381 }
1365 1382
1366 1383
1367 void GenerationVariant::RestoreAffectedRegisters( 1384 void GenerationVariant::RestoreAffectedRegisters(
1368 RegExpMacroAssembler* assembler, 1385 RegExpMacroAssembler* assembler,
1369 int max_register, 1386 int max_register,
1370 OutSet& affected_registers) { 1387 OutSet& affected_registers) {
1371 for (int reg = max_register; reg >= 0; reg--) { 1388 for (int reg = max_register; reg >= 0; reg--) {
1372 if (affected_registers.Get(reg)) assembler->PopRegister(reg); 1389 if (affected_registers.Get(reg)) assembler->PopRegister(reg);
Erik Corry 2009/01/14 09:24:31 ... and pop registers if they are just affected by
Erik Corry 2009/01/14 09:30:13 In fact for register 0 there's no need to clear it
1373 } 1390 }
1374 } 1391 }
1375 1392
1376 1393
1377 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* assembler, 1394 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* assembler,
1378 int max_register, 1395 int max_register,
1379 OutSet& affected_registers) { 1396 OutSet& affected_registers) {
1380 for (int reg = 0; reg <= max_register; reg++) { 1397 for (int reg = 0; reg <= max_register; reg++) {
1381 if (!affected_registers.Get(reg)) { 1398 if (!affected_registers.Get(reg)) {
1382 continue; 1399 continue;
1383 } 1400 }
1384 int value = 0; 1401 int value = 0;
1385 bool absolute = false; 1402 bool absolute = false;
1403 bool clear = false;
1386 int store_position = -1; 1404 int store_position = -1;
1387 // This is a little tricky because we are scanning the actions in reverse 1405 // This is a little tricky because we are scanning the actions in reverse
1388 // historical order (newest first). 1406 // historical order (newest first).
1389 for (DeferredAction* action = actions_; 1407 for (DeferredAction* action = actions_;
1390 action != NULL; 1408 action != NULL;
1391 action = action->next()) { 1409 action = action->next()) {
1392 if (action->reg() == reg) { 1410 if (action->Mentions(reg)) {
1393 switch (action->type()) { 1411 switch (action->type()) {
1394 case ActionNode::SET_REGISTER: { 1412 case ActionNode::SET_REGISTER: {
1395 GenerationVariant::DeferredSetRegister* psr = 1413 GenerationVariant::DeferredSetRegister* psr =
1396 static_cast<GenerationVariant::DeferredSetRegister*>(action); 1414 static_cast<GenerationVariant::DeferredSetRegister*>(action);
1397 value += psr->value(); 1415 value += psr->value();
1398 absolute = true; 1416 absolute = true;
1399 ASSERT_EQ(store_position, -1); 1417 ASSERT_EQ(store_position, -1);
1418 ASSERT(!clear);
1400 break; 1419 break;
1401 } 1420 }
1402 case ActionNode::INCREMENT_REGISTER: 1421 case ActionNode::INCREMENT_REGISTER:
1403 if (!absolute) { 1422 if (!absolute) {
1404 value++; 1423 value++;
1405 } 1424 }
1406 ASSERT_EQ(store_position, -1); 1425 ASSERT_EQ(store_position, -1);
1426 ASSERT(!clear);
1407 break; 1427 break;
1408 case ActionNode::STORE_POSITION: { 1428 case ActionNode::STORE_POSITION: {
Erik Corry 2009/01/14 09:24:31 We should be ignoring a store position that we fin
Christian Plesner Hansen 2009/01/14 11:31:35 Fixed
1409 GenerationVariant::DeferredCapture* pc = 1429 GenerationVariant::DeferredCapture* pc =
1410 static_cast<GenerationVariant::DeferredCapture*>(action); 1430 static_cast<GenerationVariant::DeferredCapture*>(action);
1411 if (store_position == -1) { 1431 if (store_position == -1) {
1412 store_position = pc->cp_offset(); 1432 store_position = pc->cp_offset();
1413 } 1433 }
1414 ASSERT(!absolute); 1434 ASSERT(!absolute);
1415 ASSERT_EQ(value, 0); 1435 ASSERT_EQ(value, 0);
1416 break; 1436 break;
1417 } 1437 }
1438 case ActionNode::CLEAR_CAPTURES: {
Erik Corry 2009/01/14 09:24:31 ...and we should be ignoring a clear that we find
Christian Plesner Hansen 2009/01/14 11:31:35 Fixed
1439 clear = true;
1440 ASSERT(!absolute);
1441 ASSERT_EQ(value, 0);
1442 break;
1443 }
1418 default: 1444 default:
1419 UNREACHABLE(); 1445 UNREACHABLE();
1420 break; 1446 break;
1421 } 1447 }
1422 } 1448 }
1423 } 1449 }
1424 if (store_position != -1) { 1450 if (store_position != -1) {
1425 assembler->WriteCurrentPositionToRegister(reg, store_position); 1451 assembler->WriteCurrentPositionToRegister(reg, store_position);
1426 } else { 1452 } else if (clear) {
1427 if (absolute) { 1453 assembler->ClearRegister(reg);
1428 assembler->SetRegister(reg, value); 1454 } else if (absolute) {
1429 } else { 1455 assembler->SetRegister(reg, value);
1430 if (value != 0) { 1456 } else if (value != 0) {
1431 assembler->AdvanceRegister(reg, value); 1457 assembler->AdvanceRegister(reg, value);
1432 }
1433 }
1434 } 1458 }
1435 } 1459 }
1436 } 1460 }
1437 1461
1438 1462
1439 // This is called as we come into a loop choice node and some other tricky 1463 // This is called as we come into a loop choice node and some other tricky
1440 // nodes. It normalises the state of the code generator to ensure we can 1464 // nodes. It normalises the state of the code generator to ensure we can
1441 // generate generic code. 1465 // generate generic code.
1442 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) { 1466 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
1443 RegExpMacroAssembler* assembler = compiler->macro_assembler(); 1467 RegExpMacroAssembler* assembler = compiler->macro_assembler();
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1579 } 1603 }
1580 1604
1581 1605
1582 ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) { 1606 ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
1583 ActionNode* result = new ActionNode(STORE_POSITION, on_success); 1607 ActionNode* result = new ActionNode(STORE_POSITION, on_success);
1584 result->data_.u_position_register.reg = reg; 1608 result->data_.u_position_register.reg = reg;
1585 return result; 1609 return result;
1586 } 1610 }
1587 1611
1588 1612
1613 ActionNode* ActionNode::ClearCaptures(Interval range,
1614 RegExpNode* on_success) {
1615 ActionNode* result = new ActionNode(CLEAR_CAPTURES, on_success);
1616 result->data_.u_clear_captures.range_from = range.from();
1617 result->data_.u_clear_captures.range_to = range.to();
1618 return result;
1619 }
1620
1621
1589 ActionNode* ActionNode::BeginSubmatch(int stack_reg, 1622 ActionNode* ActionNode::BeginSubmatch(int stack_reg,
1590 int position_reg, 1623 int position_reg,
1591 RegExpNode* on_success) { 1624 RegExpNode* on_success) {
1592 ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success); 1625 ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success);
1593 result->data_.u_submatch.stack_pointer_register = stack_reg; 1626 result->data_.u_submatch.stack_pointer_register = stack_reg;
1594 result->data_.u_submatch.current_position_register = position_reg; 1627 result->data_.u_submatch.current_position_register = position_reg;
1595 return result; 1628 return result;
1596 } 1629 }
1597 1630
1598 1631
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
2260 pos->mask &= other_pos->mask; 2293 pos->mask &= other_pos->mask;
2261 pos->value &= pos->mask; 2294 pos->value &= pos->mask;
2262 other_pos->value &= pos->mask; 2295 other_pos->value &= pos->mask;
2263 uc16 differing_bits = (pos->value ^ other_pos->value); 2296 uc16 differing_bits = (pos->value ^ other_pos->value);
2264 pos->mask &= ~differing_bits; 2297 pos->mask &= ~differing_bits;
2265 pos->value &= pos->mask; 2298 pos->value &= pos->mask;
2266 } 2299 }
2267 } 2300 }
2268 2301
2269 2302
2303 class VisitMarker {
2304 public:
2305 VisitMarker(NodeInfo* info) : info_(info) {
2306 ASSERT(!info->visited);
2307 info->visited = true;
2308 }
2309 ~VisitMarker() {
2310 info_->visited = false;
2311 }
2312 private:
2313 NodeInfo* info_;
2314 };
2315
2316
2270 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, 2317 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
2271 RegExpCompiler* compiler, 2318 RegExpCompiler* compiler,
2272 int characters_filled_in) { 2319 int characters_filled_in) {
2273 if (body_can_be_zero_length_) return; 2320 if (body_can_be_zero_length_ || info()->visited) return;
2321 VisitMarker marker(info());
2274 return ChoiceNode::GetQuickCheckDetails(details, 2322 return ChoiceNode::GetQuickCheckDetails(details,
2275 compiler, 2323 compiler,
2276 characters_filled_in); 2324 characters_filled_in);
2277 } 2325 }
2278 2326
2279 2327
2280 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, 2328 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
2281 RegExpCompiler* compiler, 2329 RegExpCompiler* compiler,
2282 int characters_filled_in) { 2330 int characters_filled_in) {
2283 int choice_count = alternatives_->length(); 2331 int choice_count = alternatives_->length();
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after
2836 bool preload_is_current = 2884 bool preload_is_current =
2837 (current_variant->characters_preloaded() == preload_characters); 2885 (current_variant->characters_preloaded() == preload_characters);
2838 bool preload_has_checked_bounds = preload_is_current; 2886 bool preload_has_checked_bounds = preload_is_current;
2839 2887
2840 AlternativeGenerationList alt_gens(choice_count); 2888 AlternativeGenerationList alt_gens(choice_count);
2841 2889
2842 // For now we just call all choices one after the other. The idea ultimately 2890 // For now we just call all choices one after the other. The idea ultimately
2843 // is to use the Dispatch table to try only the relevant ones. 2891 // is to use the Dispatch table to try only the relevant ones.
2844 for (int i = first_normal_choice; i < choice_count; i++) { 2892 for (int i = first_normal_choice; i < choice_count; i++) {
2845 GuardedAlternative alternative = alternatives_->at(i); 2893 GuardedAlternative alternative = alternatives_->at(i);
2846 AlternativeGeneration* alt_gen(alt_gens.at(i)); 2894 AlternativeGeneration* alt_gen = alt_gens.at(i);
2847 alt_gen->quick_check_details.set_characters(preload_characters); 2895 alt_gen->quick_check_details.set_characters(preload_characters);
2848 ZoneList<Guard*>* guards = alternative.guards(); 2896 ZoneList<Guard*>* guards = alternative.guards();
2849 int guard_count = (guards == NULL) ? 0 : guards->length(); 2897 int guard_count = (guards == NULL) ? 0 : guards->length();
2850 GenerationVariant new_variant(*current_variant); 2898 GenerationVariant new_variant(*current_variant);
2851 new_variant.set_characters_preloaded(preload_is_current ? 2899 new_variant.set_characters_preloaded(preload_is_current ?
2852 preload_characters : 2900 preload_characters :
2853 0); 2901 0);
2854 if (preload_has_checked_bounds) { 2902 if (preload_has_checked_bounds) {
2855 new_variant.set_bound_checked_up_to(preload_characters); 2903 new_variant.set_bound_checked_up_to(preload_characters);
2856 } 2904 }
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2995 new_variant.add_action(&new_increment); 3043 new_variant.add_action(&new_increment);
2996 return on_success()->Emit(compiler, &new_variant); 3044 return on_success()->Emit(compiler, &new_variant);
2997 } 3045 }
2998 case SET_REGISTER: { 3046 case SET_REGISTER: {
2999 GenerationVariant::DeferredSetRegister 3047 GenerationVariant::DeferredSetRegister
3000 new_set(data_.u_store_register.reg, data_.u_store_register.value); 3048 new_set(data_.u_store_register.reg, data_.u_store_register.value);
3001 GenerationVariant new_variant = *variant; 3049 GenerationVariant new_variant = *variant;
3002 new_variant.add_action(&new_set); 3050 new_variant.add_action(&new_set);
3003 return on_success()->Emit(compiler, &new_variant); 3051 return on_success()->Emit(compiler, &new_variant);
3004 } 3052 }
3053 case CLEAR_CAPTURES: {
3054 GenerationVariant::DeferredClearCaptures
3055 new_capture(Interval(data_.u_clear_captures.range_from,
3056 data_.u_clear_captures.range_to));
3057 GenerationVariant new_variant = *variant;
3058 new_variant.add_action(&new_capture);
3059 return on_success()->Emit(compiler, &new_variant);
3060 }
3005 case BEGIN_SUBMATCH: 3061 case BEGIN_SUBMATCH:
3006 if (!variant->is_trivial()) return variant->Flush(compiler, this); 3062 if (!variant->is_trivial()) return variant->Flush(compiler, this);
3007 assembler->WriteCurrentPositionToRegister( 3063 assembler->WriteCurrentPositionToRegister(
3008 data_.u_submatch.current_position_register, 0); 3064 data_.u_submatch.current_position_register, 0);
3009 assembler->WriteStackPointerToRegister( 3065 assembler->WriteStackPointerToRegister(
3010 data_.u_submatch.stack_pointer_register); 3066 data_.u_submatch.stack_pointer_register);
3011 return on_success()->Emit(compiler, variant); 3067 return on_success()->Emit(compiler, variant);
3012 case EMPTY_MATCH_CHECK: { 3068 case EMPTY_MATCH_CHECK: {
3013 int start_pos_reg = data_.u_empty_match_check.start_register; 3069 int start_pos_reg = data_.u_empty_match_check.start_register;
3014 int stored_pos = 0; 3070 int stored_pos = 0;
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
3358 break; 3414 break;
3359 case ActionNode::POSITIVE_SUBMATCH_SUCCESS: 3415 case ActionNode::POSITIVE_SUBMATCH_SUCCESS:
3360 stream()->Add("label=\"escape\", shape=septagon"); 3416 stream()->Add("label=\"escape\", shape=septagon");
3361 break; 3417 break;
3362 case ActionNode::EMPTY_MATCH_CHECK: 3418 case ActionNode::EMPTY_MATCH_CHECK:
3363 stream()->Add("label=\"$%i=$pos?,$%i<%i?\", shape=septagon", 3419 stream()->Add("label=\"$%i=$pos?,$%i<%i?\", shape=septagon",
3364 that->data_.u_empty_match_check.start_register, 3420 that->data_.u_empty_match_check.start_register,
3365 that->data_.u_empty_match_check.repetition_register, 3421 that->data_.u_empty_match_check.repetition_register,
3366 that->data_.u_empty_match_check.repetition_limit); 3422 that->data_.u_empty_match_check.repetition_limit);
3367 break; 3423 break;
3424 case ActionNode::CLEAR_CAPTURES: {
3425 stream()->Add("label=\"clear $%i to $%i\", shape=septagon",
3426 that->data_.u_clear_captures.range_from,
3427 that->data_.u_clear_captures.range_to);
3428 break;
3429 }
3368 } 3430 }
3369 stream()->Add("];\n"); 3431 stream()->Add("];\n");
3370 PrintAttributes(that); 3432 PrintAttributes(that);
3371 RegExpNode* successor = that->on_success(); 3433 RegExpNode* successor = that->on_success();
3372 stream()->Add(" n%p -> n%p;\n", that, successor); 3434 stream()->Add(" n%p -> n%p;\n", that, successor);
3373 Visit(successor); 3435 Visit(successor);
3374 } 3436 }
3375 3437
3376 3438
3377 class DispatchTableDumper { 3439 class DispatchTableDumper {
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
3585 3647
3586 // If we know that we cannot match zero length then things are a little 3648 // If we know that we cannot match zero length then things are a little
3587 // simpler since we don't need to make the special zero length match check 3649 // simpler since we don't need to make the special zero length match check
3588 // from step 2.1. If the min and max are small we can unroll a little in 3650 // from step 2.1. If the min and max are small we can unroll a little in
3589 // this case. 3651 // this case.
3590 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} 3652 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,}
3591 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} 3653 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3}
3592 if (max == 0) return on_success; // This can happen due to recursion. 3654 if (max == 0) return on_success; // This can happen due to recursion.
3593 bool body_can_be_empty = (body->min_match() == 0); 3655 bool body_can_be_empty = (body->min_match() == 0);
3594 int body_start_reg = RegExpCompiler::kNoRegister; 3656 int body_start_reg = RegExpCompiler::kNoRegister;
3657 Interval capture_registers = body->CaptureRegisters();
3658 bool needs_capture_clearing = !capture_registers.is_empty();
3595 if (body_can_be_empty) { 3659 if (body_can_be_empty) {
3596 body_start_reg = compiler->AllocateRegister(); 3660 body_start_reg = compiler->AllocateRegister();
3597 } else { 3661 } else if (!needs_capture_clearing) {
Erik Corry 2009/01/14 09:24:31 Surely it's OK to unroll and no need to clear capt
3662 // Only unroll if there are no captures and the body can't be
3663 // empty.
3598 if (min > 0 && min <= kMaxUnrolledMinMatches) { 3664 if (min > 0 && min <= kMaxUnrolledMinMatches) {
3599 int new_max = (max == kInfinity) ? max : max - min; 3665 int new_max = (max == kInfinity) ? max : max - min;
3600 // Recurse once to get the loop or optional matches after the fixed ones. 3666 // Recurse once to get the loop or optional matches after the fixed ones.
3601 RegExpNode* answer = 3667 RegExpNode* answer =
3602 ToNode(0, new_max, is_greedy, body, compiler, on_success); 3668 ToNode(0, new_max, is_greedy, body, compiler, on_success);
3603 // Unroll the forced matches from 0 to min. This can cause chains of 3669 // Unroll the forced matches from 0 to min. This can cause chains of
3604 // TextNodes (which the parser does not generate). These should be 3670 // TextNodes (which the parser does not generate). These should be
3605 // combined if it turns out they hinder good code generation. 3671 // combined if it turns out they hinder good code generation.
3606 for (int i = 0; i < min; i++) { 3672 for (int i = 0; i < min; i++) {
3607 answer = body->ToNode(compiler, answer); 3673 answer = body->ToNode(compiler, answer);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
3645 reg_ctr, 3711 reg_ctr,
3646 min, 3712 min,
3647 loop_return); 3713 loop_return);
3648 } 3714 }
3649 RegExpNode* body_node = body->ToNode(compiler, loop_return); 3715 RegExpNode* body_node = body->ToNode(compiler, loop_return);
3650 if (body_can_be_empty) { 3716 if (body_can_be_empty) {
3651 // If the body can be empty we need to store the start position 3717 // If the body can be empty we need to store the start position
3652 // so we can bail out if it was empty. 3718 // so we can bail out if it was empty.
3653 body_node = ActionNode::StorePosition(body_start_reg, body_node); 3719 body_node = ActionNode::StorePosition(body_start_reg, body_node);
3654 } 3720 }
3721 if (needs_capture_clearing) {
3722 // Before entering the body of this loop we need to clear captures.
3723 body_node = ActionNode::ClearCaptures(capture_registers, body_node);
3724 }
3655 GuardedAlternative body_alt(body_node); 3725 GuardedAlternative body_alt(body_node);
3656 if (has_max) { 3726 if (has_max) {
3657 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max); 3727 Guard* body_guard = new Guard(reg_ctr, Guard::LT, max);
3658 body_alt.AddGuard(body_guard); 3728 body_alt.AddGuard(body_guard);
3659 } 3729 }
3660 GuardedAlternative rest_alt(on_success); 3730 GuardedAlternative rest_alt(on_success);
3661 if (has_min) { 3731 if (has_min) {
3662 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min); 3732 Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min);
3663 rest_alt.AddGuard(rest_guard); 3733 rest_alt.AddGuard(rest_guard);
3664 } 3734 }
(...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after
4485 EmbeddedVector<byte, 1024> codes; 4555 EmbeddedVector<byte, 1024> codes;
4486 RegExpMacroAssemblerIrregexp macro_assembler(codes); 4556 RegExpMacroAssemblerIrregexp macro_assembler(codes);
4487 return compiler.Assemble(&macro_assembler, 4557 return compiler.Assemble(&macro_assembler,
4488 node, 4558 node,
4489 data->capture_count, 4559 data->capture_count,
4490 pattern); 4560 pattern);
4491 } 4561 }
4492 4562
4493 4563
4494 }} // namespace v8::internal 4564 }} // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698