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 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
4485 EmbeddedVector<byte, 1024> codes; | 4555 EmbeddedVector<byte, 1024> codes; |
4486 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4556 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
4487 return compiler.Assemble(¯o_assembler, | 4557 return compiler.Assemble(¯o_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 |
OLD | NEW |