Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 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 |