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 1092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1103 // space. | 1103 // space. |
1104 // * The current state is virtualized. | 1104 // * The current state is virtualized. |
1105 // This is used to defer expensive operations until it is clear that they | 1105 // This is used to defer expensive operations until it is clear that they |
1106 // are needed and to generate code for a node more than once, allowing | 1106 // are needed and to generate code for a node more than once, allowing |
1107 // specialized an efficient versions of the code to be created. This is | 1107 // specialized an efficient versions of the code to be created. This is |
1108 // explained in the section below. | 1108 // explained in the section below. |
1109 // | 1109 // |
1110 // Execution state virtualization. | 1110 // Execution state virtualization. |
1111 // | 1111 // |
1112 // Instead of emitting code, nodes that manipulate the state can record their | 1112 // Instead of emitting code, nodes that manipulate the state can record their |
1113 // manipulation in an object called the GenerationVariant. The | 1113 // manipulation in an object called the Trace. The Trace object can record a |
1114 // GenerationVariant object can record a current position offset, an | 1114 // current position offset, an optional backtrack code location on the top of |
1115 // optional backtrack code location on the top of the virtualized backtrack | 1115 // the virtualized backtrack stack and some register changes. When a node is |
1116 // stack and some register changes. When a node is to be emitted it can flush | 1116 // to be emitted it can flush the Trace or update it. Flushing the Trace |
1117 // the GenerationVariant or update it. Flushing the GenerationVariant | |
1118 // will emit code to bring the actual state into line with the virtual state. | 1117 // will emit code to bring the actual state into line with the virtual state. |
1119 // Avoiding flushing the state can postpone some work (eg updates of capture | 1118 // Avoiding flushing the state can postpone some work (eg updates of capture |
1120 // registers). Postponing work can save time when executing the regular | 1119 // registers). Postponing work can save time when executing the regular |
1121 // expression since it may be found that the work never has to be done as a | 1120 // expression since it may be found that the work never has to be done as a |
1122 // failure to match can occur. In addition it is much faster to jump to a | 1121 // failure to match can occur. In addition it is much faster to jump to a |
1123 // known backtrack code location than it is to pop an unknown backtrack | 1122 // known backtrack code location than it is to pop an unknown backtrack |
1124 // location from the stack and jump there. | 1123 // location from the stack and jump there. |
1125 // | 1124 // |
1126 // The virtual state found in the GenerationVariant affects code generation. | 1125 // The virtual state found in the Trace affects code generation. For example |
1127 // For example the virtual state contains the difference between the actual | 1126 // the virtual state contains the difference between the actual current |
1128 // current position and the virtual current position, and matching code needs | 1127 // position and the virtual current position, and matching code needs to use |
1129 // to use this offset to attempt a match in the correct location of the input | 1128 // this offset to attempt a match in the correct location of the input |
1130 // string. Therefore code generated for a non-trivial GenerationVariant is | 1129 // string. Therefore code generated for a non-trivial trace is specialized |
1131 // specialized to that GenerationVariant. The code generator therefore | 1130 // to that trace. The code generator therefore has the ability to generate |
1132 // has the ability to generate code for each node several times. In order to | 1131 // code for each node several times. In order to limit the size of the |
1133 // limit the size of the generated code there is an arbitrary limit on how | 1132 // generated code there is an arbitrary limit on how many specialized sets of |
1134 // many specialized sets of code may be generated for a given node. If the | 1133 // code may be generated for a given node. If the limit is reached, the |
1135 // limit is reached, the GenerationVariant is flushed and a generic version of | 1134 // trace is flushed and a generic version of the code for a node is emitted. |
1136 // the code for a node is emitted. This is subsequently used for that node. | 1135 // This is subsequently used for that node. The code emitted for non-generic |
1137 // The code emitted for non-generic GenerationVariants is not recorded in the | 1136 // trace is not recorded in the node and so it cannot currently be reused in |
1138 // node and so it cannot currently be reused in the event that code generation | 1137 // the event that code generation is requested for an identical trace. |
1139 // is requested for an identical GenerationVariant. | |
1140 | 1138 |
1141 | 1139 |
1142 void RegExpTree::AppendToText(RegExpText* text) { | 1140 void RegExpTree::AppendToText(RegExpText* text) { |
1143 UNREACHABLE(); | 1141 UNREACHABLE(); |
1144 } | 1142 } |
1145 | 1143 |
1146 | 1144 |
1147 void RegExpAtom::AppendToText(RegExpText* text) { | 1145 void RegExpAtom::AppendToText(RegExpText* text) { |
1148 text->AddElement(TextElement::Atom(this)); | 1146 text->AddElement(TextElement::Atom(this)); |
1149 } | 1147 } |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 #ifdef DEBUG | 1264 #ifdef DEBUG |
1267 if (FLAG_trace_regexp_assembler) | 1265 if (FLAG_trace_regexp_assembler) |
1268 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); | 1266 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); |
1269 else | 1267 else |
1270 #endif | 1268 #endif |
1271 macro_assembler_ = macro_assembler; | 1269 macro_assembler_ = macro_assembler; |
1272 List <RegExpNode*> work_list(0); | 1270 List <RegExpNode*> work_list(0); |
1273 work_list_ = &work_list; | 1271 work_list_ = &work_list; |
1274 Label fail; | 1272 Label fail; |
1275 macro_assembler->PushBacktrack(&fail); | 1273 macro_assembler->PushBacktrack(&fail); |
1276 GenerationVariant generic_variant; | 1274 Trace new_trace; |
1277 if (!start->Emit(this, &generic_variant)) { | 1275 if (!start->Emit(this, &new_trace)) { |
1278 fail.Unuse(); | 1276 fail.Unuse(); |
1279 return Handle<FixedArray>::null(); | 1277 return Handle<FixedArray>::null(); |
1280 } | 1278 } |
1281 macro_assembler_->Bind(&fail); | 1279 macro_assembler_->Bind(&fail); |
1282 macro_assembler_->Fail(); | 1280 macro_assembler_->Fail(); |
1283 while (!work_list.is_empty()) { | 1281 while (!work_list.is_empty()) { |
1284 if (!work_list.RemoveLast()->Emit(this, &generic_variant)) { | 1282 if (!work_list.RemoveLast()->Emit(this, &new_trace)) { |
1285 return Handle<FixedArray>::null(); | 1283 return Handle<FixedArray>::null(); |
1286 } | 1284 } |
1287 } | 1285 } |
1288 Handle<FixedArray> array = | 1286 Handle<FixedArray> array = |
1289 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); | 1287 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); |
1290 array->set(RegExpImpl::kIrregexpImplementationIndex, | 1288 array->set(RegExpImpl::kIrregexpImplementationIndex, |
1291 Smi::FromInt(macro_assembler_->Implementation())); | 1289 Smi::FromInt(macro_assembler_->Implementation())); |
1292 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, | 1290 array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex, |
1293 Smi::FromInt(next_register_)); | 1291 Smi::FromInt(next_register_)); |
1294 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, | 1292 array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex, |
1295 Smi::FromInt(capture_count)); | 1293 Smi::FromInt(capture_count)); |
1296 Handle<Object> code = macro_assembler_->GetCode(pattern); | 1294 Handle<Object> code = macro_assembler_->GetCode(pattern); |
1297 array->set(RegExpImpl::kIrregexpCodeIndex, *code); | 1295 array->set(RegExpImpl::kIrregexpCodeIndex, *code); |
1298 work_list_ = NULL; | 1296 work_list_ = NULL; |
1299 #ifdef DEBUG | 1297 #ifdef DEBUG |
1300 if (FLAG_trace_regexp_assembler) { | 1298 if (FLAG_trace_regexp_assembler) { |
1301 delete macro_assembler_; | 1299 delete macro_assembler_; |
1302 } | 1300 } |
1303 #endif | 1301 #endif |
1304 return array; | 1302 return array; |
1305 } | 1303 } |
1306 | 1304 |
1307 bool GenerationVariant::DeferredAction::Mentions(int that) { | 1305 bool Trace::DeferredAction::Mentions(int that) { |
1308 if (type() == ActionNode::CLEAR_CAPTURES) { | 1306 if (type() == ActionNode::CLEAR_CAPTURES) { |
1309 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); | 1307 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); |
1310 return range.Contains(that); | 1308 return range.Contains(that); |
1311 } else { | 1309 } else { |
1312 return reg() == that; | 1310 return reg() == that; |
1313 } | 1311 } |
1314 } | 1312 } |
1315 | 1313 |
1316 | 1314 |
1317 bool GenerationVariant::mentions_reg(int reg) { | 1315 bool Trace::mentions_reg(int reg) { |
1318 for (DeferredAction* action = actions_; | 1316 for (DeferredAction* action = actions_; |
1319 action != NULL; | 1317 action != NULL; |
1320 action = action->next()) { | 1318 action = action->next()) { |
1321 if (action->Mentions(reg)) | 1319 if (action->Mentions(reg)) |
1322 return true; | 1320 return true; |
1323 } | 1321 } |
1324 return false; | 1322 return false; |
1325 } | 1323 } |
1326 | 1324 |
1327 | 1325 |
1328 bool GenerationVariant::GetStoredPosition(int reg, int* cp_offset) { | 1326 bool Trace::GetStoredPosition(int reg, int* cp_offset) { |
1329 ASSERT_EQ(0, *cp_offset); | 1327 ASSERT_EQ(0, *cp_offset); |
1330 for (DeferredAction* action = actions_; | 1328 for (DeferredAction* action = actions_; |
1331 action != NULL; | 1329 action != NULL; |
1332 action = action->next()) { | 1330 action = action->next()) { |
1333 if (action->Mentions(reg)) { | 1331 if (action->Mentions(reg)) { |
1334 if (action->type() == ActionNode::STORE_POSITION) { | 1332 if (action->type() == ActionNode::STORE_POSITION) { |
1335 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); | 1333 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); |
1336 return true; | 1334 return true; |
1337 } else { | 1335 } else { |
1338 return false; | 1336 return false; |
1339 } | 1337 } |
1340 } | 1338 } |
1341 } | 1339 } |
1342 return false; | 1340 return false; |
1343 } | 1341 } |
1344 | 1342 |
1345 | 1343 |
1346 int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) { | 1344 int Trace::FindAffectedRegisters(OutSet* affected_registers) { |
1347 int max_register = RegExpCompiler::kNoRegister; | 1345 int max_register = RegExpCompiler::kNoRegister; |
1348 for (DeferredAction* action = actions_; | 1346 for (DeferredAction* action = actions_; |
1349 action != NULL; | 1347 action != NULL; |
1350 action = action->next()) { | 1348 action = action->next()) { |
1351 if (action->type() == ActionNode::CLEAR_CAPTURES) { | 1349 if (action->type() == ActionNode::CLEAR_CAPTURES) { |
1352 Interval range = static_cast<DeferredClearCaptures*>(action)->range(); | 1350 Interval range = static_cast<DeferredClearCaptures*>(action)->range(); |
1353 for (int i = range.from(); i <= range.to(); i++) | 1351 for (int i = range.from(); i <= range.to(); i++) |
1354 affected_registers->Set(i); | 1352 affected_registers->Set(i); |
1355 if (range.to() > max_register) max_register = range.to(); | 1353 if (range.to() > max_register) max_register = range.to(); |
1356 } else { | 1354 } else { |
1357 affected_registers->Set(action->reg()); | 1355 affected_registers->Set(action->reg()); |
1358 if (action->reg() > max_register) max_register = action->reg(); | 1356 if (action->reg() > max_register) max_register = action->reg(); |
1359 } | 1357 } |
1360 } | 1358 } |
1361 return max_register; | 1359 return max_register; |
1362 } | 1360 } |
1363 | 1361 |
1364 | 1362 |
1365 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler, | 1363 void Trace::PushAffectedRegisters(RegExpMacroAssembler* assembler, |
1366 int max_register, | 1364 int max_register, |
1367 OutSet& affected_registers) { | 1365 OutSet& affected_registers) { |
1368 // Stay safe and check every half times the limit. | 1366 // Stay safe and check every half times the limit. |
1369 // (Round up in case the limit is 1). | 1367 // (Round up in case the limit is 1). |
1370 int push_limit = (assembler->stack_limit_slack() + 1) / 2; | 1368 int push_limit = (assembler->stack_limit_slack() + 1) / 2; |
1371 for (int reg = 0, pushes = 0; reg <= max_register; reg++) { | 1369 for (int reg = 0, pushes = 0; reg <= max_register; reg++) { |
1372 if (affected_registers.Get(reg)) { | 1370 if (affected_registers.Get(reg)) { |
1373 pushes++; | 1371 pushes++; |
1374 RegExpMacroAssembler::StackCheckFlag check_stack_limit = | 1372 RegExpMacroAssembler::StackCheckFlag check_stack_limit = |
1375 (pushes % push_limit) == 0 ? | 1373 (pushes % push_limit) == 0 ? |
1376 RegExpMacroAssembler::kCheckStackLimit : | 1374 RegExpMacroAssembler::kCheckStackLimit : |
1377 RegExpMacroAssembler::kNoStackLimitCheck; | 1375 RegExpMacroAssembler::kNoStackLimitCheck; |
1378 assembler->PushRegister(reg, check_stack_limit); | 1376 assembler->PushRegister(reg, check_stack_limit); |
1379 } | 1377 } |
1380 } | 1378 } |
1381 } | 1379 } |
1382 | 1380 |
1383 | 1381 |
1384 void GenerationVariant::RestoreAffectedRegisters( | 1382 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler, |
1385 RegExpMacroAssembler* assembler, | 1383 int max_register, |
1386 int max_register, | 1384 OutSet& affected_registers) { |
1387 OutSet& affected_registers) { | |
1388 for (int reg = max_register; reg >= 0; reg--) { | 1385 for (int reg = max_register; reg >= 0; reg--) { |
1389 if (affected_registers.Get(reg)) assembler->PopRegister(reg); | 1386 if (affected_registers.Get(reg)) assembler->PopRegister(reg); |
1390 } | 1387 } |
1391 } | 1388 } |
1392 | 1389 |
1393 | 1390 |
1394 void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* assembler, | 1391 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler, |
1395 int max_register, | 1392 int max_register, |
1396 OutSet& affected_registers) { | 1393 OutSet& affected_registers) { |
1397 for (int reg = 0; reg <= max_register; reg++) { | 1394 for (int reg = 0; reg <= max_register; reg++) { |
1398 if (!affected_registers.Get(reg)) { | 1395 if (!affected_registers.Get(reg)) { |
1399 continue; | 1396 continue; |
1400 } | 1397 } |
1401 int value = 0; | 1398 int value = 0; |
1402 bool absolute = false; | 1399 bool absolute = false; |
1403 bool clear = false; | 1400 bool clear = false; |
1404 int store_position = -1; | 1401 int store_position = -1; |
1405 // This is a little tricky because we are scanning the actions in reverse | 1402 // This is a little tricky because we are scanning the actions in reverse |
1406 // historical order (newest first). | 1403 // historical order (newest first). |
1407 for (DeferredAction* action = actions_; | 1404 for (DeferredAction* action = actions_; |
1408 action != NULL; | 1405 action != NULL; |
1409 action = action->next()) { | 1406 action = action->next()) { |
1410 if (action->Mentions(reg)) { | 1407 if (action->Mentions(reg)) { |
1411 switch (action->type()) { | 1408 switch (action->type()) { |
1412 case ActionNode::SET_REGISTER: { | 1409 case ActionNode::SET_REGISTER: { |
1413 GenerationVariant::DeferredSetRegister* psr = | 1410 Trace::DeferredSetRegister* psr = |
1414 static_cast<GenerationVariant::DeferredSetRegister*>(action); | 1411 static_cast<Trace::DeferredSetRegister*>(action); |
1415 value += psr->value(); | 1412 value += psr->value(); |
1416 absolute = true; | 1413 absolute = true; |
1417 ASSERT_EQ(store_position, -1); | 1414 ASSERT_EQ(store_position, -1); |
1418 ASSERT(!clear); | 1415 ASSERT(!clear); |
1419 break; | 1416 break; |
1420 } | 1417 } |
1421 case ActionNode::INCREMENT_REGISTER: | 1418 case ActionNode::INCREMENT_REGISTER: |
1422 if (!absolute) { | 1419 if (!absolute) { |
1423 value++; | 1420 value++; |
1424 } | 1421 } |
1425 ASSERT_EQ(store_position, -1); | 1422 ASSERT_EQ(store_position, -1); |
1426 ASSERT(!clear); | 1423 ASSERT(!clear); |
1427 break; | 1424 break; |
1428 case ActionNode::STORE_POSITION: { | 1425 case ActionNode::STORE_POSITION: { |
1429 GenerationVariant::DeferredCapture* pc = | 1426 Trace::DeferredCapture* pc = |
1430 static_cast<GenerationVariant::DeferredCapture*>(action); | 1427 static_cast<Trace::DeferredCapture*>(action); |
1431 if (!clear && store_position == -1) { | 1428 if (!clear && store_position == -1) { |
1432 store_position = pc->cp_offset(); | 1429 store_position = pc->cp_offset(); |
1433 } | 1430 } |
1434 ASSERT(!absolute); | 1431 ASSERT(!absolute); |
1435 ASSERT_EQ(value, 0); | 1432 ASSERT_EQ(value, 0); |
1436 break; | 1433 break; |
1437 } | 1434 } |
1438 case ActionNode::CLEAR_CAPTURES: { | 1435 case ActionNode::CLEAR_CAPTURES: { |
1439 // Since we're scanning in reverse order, if we've already | 1436 // Since we're scanning in reverse order, if we've already |
1440 // set the position we have to ignore historically earlier | 1437 // set the position we have to ignore historically earlier |
(...skipping 19 matching lines...) Expand all Loading... |
1460 } else if (value != 0) { | 1457 } else if (value != 0) { |
1461 assembler->AdvanceRegister(reg, value); | 1458 assembler->AdvanceRegister(reg, value); |
1462 } | 1459 } |
1463 } | 1460 } |
1464 } | 1461 } |
1465 | 1462 |
1466 | 1463 |
1467 // This is called as we come into a loop choice node and some other tricky | 1464 // This is called as we come into a loop choice node and some other tricky |
1468 // nodes. It normalises the state of the code generator to ensure we can | 1465 // nodes. It normalises the state of the code generator to ensure we can |
1469 // generate generic code. | 1466 // generate generic code. |
1470 bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) { | 1467 bool Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
1471 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1468 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
1472 | 1469 |
1473 ASSERT(actions_ != NULL || | 1470 ASSERT(actions_ != NULL || |
1474 cp_offset_ != 0 || | 1471 cp_offset_ != 0 || |
1475 backtrack() != NULL || | 1472 backtrack() != NULL || |
1476 characters_preloaded_ != 0 || | 1473 characters_preloaded_ != 0 || |
1477 quick_check_performed_.characters() != 0 || | 1474 quick_check_performed_.characters() != 0 || |
1478 bound_checked_up_to_ != 0); | 1475 bound_checked_up_to_ != 0); |
1479 | 1476 |
1480 if (actions_ == NULL && backtrack() == NULL) { | 1477 if (actions_ == NULL && backtrack() == NULL) { |
1481 // Here we just have some deferred cp advances to fix and we are back to | 1478 // Here we just have some deferred cp advances to fix and we are back to |
1482 // a normal situation. We may also have to forget some information gained | 1479 // a normal situation. We may also have to forget some information gained |
1483 // through a quick check that was already performed. | 1480 // through a quick check that was already performed. |
1484 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); | 1481 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); |
1485 // Create a new trivial state and generate the node with that. | 1482 // Create a new trivial state and generate the node with that. |
1486 GenerationVariant new_state; | 1483 Trace new_state; |
1487 return successor->Emit(compiler, &new_state); | 1484 return successor->Emit(compiler, &new_state); |
1488 } | 1485 } |
1489 | 1486 |
1490 // Generate deferred actions here along with code to undo them again. | 1487 // Generate deferred actions here along with code to undo them again. |
1491 OutSet affected_registers; | 1488 OutSet affected_registers; |
1492 int max_register = FindAffectedRegisters(&affected_registers); | 1489 int max_register = FindAffectedRegisters(&affected_registers); |
1493 PushAffectedRegisters(assembler, max_register, affected_registers); | 1490 PushAffectedRegisters(assembler, max_register, affected_registers); |
1494 PerformDeferredActions(assembler, max_register, affected_registers); | 1491 PerformDeferredActions(assembler, max_register, affected_registers); |
1495 if (backtrack() != NULL) { | 1492 if (backtrack() != NULL) { |
1496 // Here we have a concrete backtrack location. These are set up by choice | 1493 // Here we have a concrete backtrack location. These are set up by choice |
1497 // nodes and so they indicate that we have a deferred save of the current | 1494 // nodes and so they indicate that we have a deferred save of the current |
1498 // position which we may need to emit here. | 1495 // position which we may need to emit here. |
1499 assembler->PushCurrentPosition(); | 1496 assembler->PushCurrentPosition(); |
1500 } | 1497 } |
1501 if (cp_offset_ != 0) { | 1498 if (cp_offset_ != 0) { |
1502 assembler->AdvanceCurrentPosition(cp_offset_); | 1499 assembler->AdvanceCurrentPosition(cp_offset_); |
1503 } | 1500 } |
1504 | 1501 |
1505 // Create a new trivial state and generate the node with that. | 1502 // Create a new trivial state and generate the node with that. |
1506 Label undo; | 1503 Label undo; |
1507 assembler->PushBacktrack(&undo); | 1504 assembler->PushBacktrack(&undo); |
1508 GenerationVariant new_state; | 1505 Trace new_state; |
1509 bool ok = successor->Emit(compiler, &new_state); | 1506 bool ok = successor->Emit(compiler, &new_state); |
1510 | 1507 |
1511 // On backtrack we need to restore state. | 1508 // On backtrack we need to restore state. |
1512 assembler->Bind(&undo); | 1509 assembler->Bind(&undo); |
1513 if (!ok) return false; | 1510 if (!ok) return false; |
1514 if (backtrack() != NULL) { | 1511 if (backtrack() != NULL) { |
1515 assembler->PopCurrentPosition(); | 1512 assembler->PopCurrentPosition(); |
1516 } | 1513 } |
1517 RestoreAffectedRegisters(assembler, max_register, affected_registers); | 1514 RestoreAffectedRegisters(assembler, max_register, affected_registers); |
1518 if (backtrack() == NULL) { | 1515 if (backtrack() == NULL) { |
1519 assembler->Backtrack(); | 1516 assembler->Backtrack(); |
1520 } else { | 1517 } else { |
1521 assembler->GoTo(backtrack()); | 1518 assembler->GoTo(backtrack()); |
1522 } | 1519 } |
1523 | 1520 |
1524 return true; | 1521 return true; |
1525 } | 1522 } |
1526 | 1523 |
1527 | 1524 |
1528 void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, | 1525 void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, Trace* trace) { |
1529 GenerationVariant* variant) { | |
1530 if (info()->at_end) { | 1526 if (info()->at_end) { |
1531 Label succeed; | 1527 Label succeed; |
1532 // LoadCurrentCharacter will go to the label if we are at the end of the | 1528 // LoadCurrentCharacter will go to the label if we are at the end of the |
1533 // input string. | 1529 // input string. |
1534 assembler->LoadCurrentCharacter(0, &succeed); | 1530 assembler->LoadCurrentCharacter(0, &succeed); |
1535 assembler->GoTo(variant->backtrack()); | 1531 assembler->GoTo(trace->backtrack()); |
1536 assembler->Bind(&succeed); | 1532 assembler->Bind(&succeed); |
1537 } | 1533 } |
1538 } | 1534 } |
1539 | 1535 |
1540 | 1536 |
1541 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, | 1537 bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) { |
1542 GenerationVariant* variant) { | 1538 if (!trace->is_trivial()) { |
1543 if (!variant->is_trivial()) { | 1539 return trace->Flush(compiler, this); |
1544 return variant->Flush(compiler, this); | |
1545 } | 1540 } |
1546 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1541 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
1547 if (!label()->is_bound()) { | 1542 if (!label()->is_bound()) { |
1548 assembler->Bind(label()); | 1543 assembler->Bind(label()); |
1549 } | 1544 } |
1550 EmitInfoChecks(assembler, variant); | 1545 EmitInfoChecks(assembler, trace); |
1551 assembler->ReadCurrentPositionFromRegister(current_position_register_); | 1546 assembler->ReadCurrentPositionFromRegister(current_position_register_); |
1552 assembler->ReadStackPointerFromRegister(stack_pointer_register_); | 1547 assembler->ReadStackPointerFromRegister(stack_pointer_register_); |
1553 // Now that we have unwound the stack we find at the top of the stack the | 1548 // Now that we have unwound the stack we find at the top of the stack the |
1554 // backtrack that the BeginSubmatch node got. | 1549 // backtrack that the BeginSubmatch node got. |
1555 assembler->Backtrack(); | 1550 assembler->Backtrack(); |
1556 return true; | 1551 return true; |
1557 } | 1552 } |
1558 | 1553 |
1559 | 1554 |
1560 bool EndNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 1555 bool EndNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
1561 if (!variant->is_trivial()) { | 1556 if (!trace->is_trivial()) { |
1562 return variant->Flush(compiler, this); | 1557 return trace->Flush(compiler, this); |
1563 } | 1558 } |
1564 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1559 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
1565 if (!label()->is_bound()) { | 1560 if (!label()->is_bound()) { |
1566 assembler->Bind(label()); | 1561 assembler->Bind(label()); |
1567 } | 1562 } |
1568 switch (action_) { | 1563 switch (action_) { |
1569 case ACCEPT: | 1564 case ACCEPT: |
1570 EmitInfoChecks(assembler, variant); | 1565 EmitInfoChecks(assembler, trace); |
1571 assembler->Succeed(); | 1566 assembler->Succeed(); |
1572 return true; | 1567 return true; |
1573 case BACKTRACK: | 1568 case BACKTRACK: |
1574 ASSERT(!info()->at_end); | 1569 ASSERT(!info()->at_end); |
1575 assembler->GoTo(variant->backtrack()); | 1570 assembler->GoTo(trace->backtrack()); |
1576 return true; | 1571 return true; |
1577 case NEGATIVE_SUBMATCH_SUCCESS: | 1572 case NEGATIVE_SUBMATCH_SUCCESS: |
1578 // This case is handled in a different virtual method. | 1573 // This case is handled in a different virtual method. |
1579 UNREACHABLE(); | 1574 UNREACHABLE(); |
1580 } | 1575 } |
1581 UNIMPLEMENTED(); | 1576 UNIMPLEMENTED(); |
1582 return false; | 1577 return false; |
1583 } | 1578 } |
1584 | 1579 |
1585 | 1580 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1667 visitor->VisitLoopChoice(this); | 1662 visitor->VisitLoopChoice(this); |
1668 } | 1663 } |
1669 | 1664 |
1670 | 1665 |
1671 // ------------------------------------------------------------------- | 1666 // ------------------------------------------------------------------- |
1672 // Emit code. | 1667 // Emit code. |
1673 | 1668 |
1674 | 1669 |
1675 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, | 1670 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, |
1676 Guard* guard, | 1671 Guard* guard, |
1677 GenerationVariant* variant) { | 1672 Trace* trace) { |
1678 switch (guard->op()) { | 1673 switch (guard->op()) { |
1679 case Guard::LT: | 1674 case Guard::LT: |
1680 ASSERT(!variant->mentions_reg(guard->reg())); | 1675 ASSERT(!trace->mentions_reg(guard->reg())); |
1681 macro_assembler->IfRegisterGE(guard->reg(), | 1676 macro_assembler->IfRegisterGE(guard->reg(), |
1682 guard->value(), | 1677 guard->value(), |
1683 variant->backtrack()); | 1678 trace->backtrack()); |
1684 break; | 1679 break; |
1685 case Guard::GEQ: | 1680 case Guard::GEQ: |
1686 ASSERT(!variant->mentions_reg(guard->reg())); | 1681 ASSERT(!trace->mentions_reg(guard->reg())); |
1687 macro_assembler->IfRegisterLT(guard->reg(), | 1682 macro_assembler->IfRegisterLT(guard->reg(), |
1688 guard->value(), | 1683 guard->value(), |
1689 variant->backtrack()); | 1684 trace->backtrack()); |
1690 break; | 1685 break; |
1691 } | 1686 } |
1692 } | 1687 } |
1693 | 1688 |
1694 | 1689 |
1695 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; | 1690 static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize; |
1696 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; | 1691 static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange; |
1697 | 1692 |
1698 | 1693 |
1699 // Only emits non-letters (things that don't have case). Only used for case | 1694 // Only emits non-letters (things that don't have case). Only used for case |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1932 } | 1927 } |
1933 macro_assembler->Bind(&success); | 1928 macro_assembler->Bind(&success); |
1934 } | 1929 } |
1935 | 1930 |
1936 | 1931 |
1937 RegExpNode::~RegExpNode() { | 1932 RegExpNode::~RegExpNode() { |
1938 } | 1933 } |
1939 | 1934 |
1940 | 1935 |
1941 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, | 1936 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, |
1942 GenerationVariant* variant) { | 1937 Trace* trace) { |
1943 // TODO(erikcorry): Implement support. | 1938 // TODO(erikcorry): Implement support. |
1944 if (info_.follows_word_interest || | 1939 if (info_.follows_word_interest || |
1945 info_.follows_newline_interest || | 1940 info_.follows_newline_interest || |
1946 info_.follows_start_interest) { | 1941 info_.follows_start_interest) { |
1947 return FAIL; | 1942 return FAIL; |
1948 } | 1943 } |
1949 | 1944 |
1950 // If we are generating a greedy loop then don't stop and don't reuse code. | 1945 // If we are generating a greedy loop then don't stop and don't reuse code. |
1951 if (variant->stop_node() != NULL) { | 1946 if (trace->stop_node() != NULL) { |
1952 return CONTINUE; | 1947 return CONTINUE; |
1953 } | 1948 } |
1954 | 1949 |
1955 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 1950 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
1956 if (variant->is_trivial()) { | 1951 if (trace->is_trivial()) { |
1957 if (label_.is_bound()) { | 1952 if (label_.is_bound()) { |
1958 // We are being asked to generate a generic version, but that's already | 1953 // We are being asked to generate a generic version, but that's already |
1959 // been done so just go to it. | 1954 // been done so just go to it. |
1960 macro_assembler->GoTo(&label_); | 1955 macro_assembler->GoTo(&label_); |
1961 return DONE; | 1956 return DONE; |
1962 } | 1957 } |
1963 if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) { | 1958 if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) { |
1964 // To avoid too deep recursion we push the node to the work queue and just | 1959 // To avoid too deep recursion we push the node to the work queue and just |
1965 // generate a goto here. | 1960 // generate a goto here. |
1966 compiler->AddWork(this); | 1961 compiler->AddWork(this); |
1967 macro_assembler->GoTo(&label_); | 1962 macro_assembler->GoTo(&label_); |
1968 return DONE; | 1963 return DONE; |
1969 } | 1964 } |
1970 // Generate generic version of the node and bind the label for later use. | 1965 // Generate generic version of the node and bind the label for later use. |
1971 macro_assembler->Bind(&label_); | 1966 macro_assembler->Bind(&label_); |
1972 return CONTINUE; | 1967 return CONTINUE; |
1973 } | 1968 } |
1974 | 1969 |
1975 // We are being asked to make a non-generic version. Keep track of how many | 1970 // We are being asked to make a non-generic version. Keep track of how many |
1976 // non-generic versions we generate so as not to overdo it. | 1971 // non-generic versions we generate so as not to overdo it. |
1977 variants_generated_++; | 1972 trace_count_++; |
1978 if (variants_generated_ < kMaxVariantsGenerated && | 1973 if (trace_count_ < kMaxCopiesCodeGenerated && |
1979 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { | 1974 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
1980 return CONTINUE; | 1975 return CONTINUE; |
1981 } | 1976 } |
1982 | 1977 |
1983 // If we get here there have been too many variants generated or recursion | 1978 // If we get here code has been generated for this node too many times or |
1984 // is too deep. Time to switch to a generic version. The code for | 1979 // recursion is too deep. Time to switch to a generic version. The code for |
1985 // generic versions above can handle deep recursion properly. | 1980 // generic versions above can handle deep recursion properly. |
1986 bool ok = variant->Flush(compiler, this); | 1981 bool ok = trace->Flush(compiler, this); |
1987 return ok ? DONE : FAIL; | 1982 return ok ? DONE : FAIL; |
1988 } | 1983 } |
1989 | 1984 |
1990 | 1985 |
1991 int ActionNode::EatsAtLeast(int recursion_depth) { | 1986 int ActionNode::EatsAtLeast(int recursion_depth) { |
1992 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; | 1987 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; |
1993 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! | 1988 if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input! |
1994 return on_success()->EatsAtLeast(recursion_depth + 1); | 1989 return on_success()->EatsAtLeast(recursion_depth + 1); |
1995 } | 1990 } |
1996 | 1991 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2057 } | 2052 } |
2058 mask_ |= (pos->mask & char_mask) << char_shift; | 2053 mask_ |= (pos->mask & char_mask) << char_shift; |
2059 value_ |= (pos->value & char_mask) << char_shift; | 2054 value_ |= (pos->value & char_mask) << char_shift; |
2060 char_shift += asc ? 8 : 16; | 2055 char_shift += asc ? 8 : 16; |
2061 } | 2056 } |
2062 return found_useful_op; | 2057 return found_useful_op; |
2063 } | 2058 } |
2064 | 2059 |
2065 | 2060 |
2066 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, | 2061 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, |
2067 GenerationVariant* variant, | 2062 Trace* trace, |
2068 bool preload_has_checked_bounds, | 2063 bool preload_has_checked_bounds, |
2069 Label* on_possible_success, | 2064 Label* on_possible_success, |
2070 QuickCheckDetails* details, | 2065 QuickCheckDetails* details, |
2071 bool fall_through_on_failure) { | 2066 bool fall_through_on_failure) { |
2072 if (details->characters() == 0) return false; | 2067 if (details->characters() == 0) return false; |
2073 GetQuickCheckDetails(details, compiler, 0); | 2068 GetQuickCheckDetails(details, compiler, 0); |
2074 if (!details->Rationalize(compiler->ascii())) return false; | 2069 if (!details->Rationalize(compiler->ascii())) return false; |
2075 uint32_t mask = details->mask(); | 2070 uint32_t mask = details->mask(); |
2076 uint32_t value = details->value(); | 2071 uint32_t value = details->value(); |
2077 | 2072 |
2078 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2073 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
2079 | 2074 |
2080 if (variant->characters_preloaded() != details->characters()) { | 2075 if (trace->characters_preloaded() != details->characters()) { |
2081 assembler->LoadCurrentCharacter(variant->cp_offset(), | 2076 assembler->LoadCurrentCharacter(trace->cp_offset(), |
2082 variant->backtrack(), | 2077 trace->backtrack(), |
2083 !preload_has_checked_bounds, | 2078 !preload_has_checked_bounds, |
2084 details->characters()); | 2079 details->characters()); |
2085 } | 2080 } |
2086 | 2081 |
2087 | 2082 |
2088 bool need_mask = true; | 2083 bool need_mask = true; |
2089 | 2084 |
2090 if (details->characters() == 1) { | 2085 if (details->characters() == 1) { |
2091 // If number of characters preloaded is 1 then we used a byte or 16 bit | 2086 // If number of characters preloaded is 1 then we used a byte or 16 bit |
2092 // load so the value is already masked down. | 2087 // load so the value is already masked down. |
(...skipping 16 matching lines...) Expand all Loading... |
2109 } | 2104 } |
2110 | 2105 |
2111 if (fall_through_on_failure) { | 2106 if (fall_through_on_failure) { |
2112 if (need_mask) { | 2107 if (need_mask) { |
2113 assembler->CheckCharacterAfterAnd(value, mask, on_possible_success); | 2108 assembler->CheckCharacterAfterAnd(value, mask, on_possible_success); |
2114 } else { | 2109 } else { |
2115 assembler->CheckCharacter(value, on_possible_success); | 2110 assembler->CheckCharacter(value, on_possible_success); |
2116 } | 2111 } |
2117 } else { | 2112 } else { |
2118 if (need_mask) { | 2113 if (need_mask) { |
2119 assembler->CheckNotCharacterAfterAnd(value, mask, variant->backtrack()); | 2114 assembler->CheckNotCharacterAfterAnd(value, mask, trace->backtrack()); |
2120 } else { | 2115 } else { |
2121 assembler->CheckNotCharacter(value, variant->backtrack()); | 2116 assembler->CheckNotCharacter(value, trace->backtrack()); |
2122 } | 2117 } |
2123 } | 2118 } |
2124 return true; | 2119 return true; |
2125 } | 2120 } |
2126 | 2121 |
2127 | 2122 |
2128 // Here is the meat of GetQuickCheckDetails (see also the comment on the | 2123 // Here is the meat of GetQuickCheckDetails (see also the comment on the |
2129 // super-class in the .h file). | 2124 // super-class in the .h file). |
2130 // | 2125 // |
2131 // We iterate along the text object, building up for each character a | 2126 // We iterate along the text object, building up for each character a |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2361 // end-of-input when loading the putative 'r'. | 2356 // end-of-input when loading the putative 'r'. |
2362 // | 2357 // |
2363 // A slight complication involves the fact that the first character may already | 2358 // A slight complication involves the fact that the first character may already |
2364 // be fetched into a register by the previous node. In this case we want to | 2359 // be fetched into a register by the previous node. In this case we want to |
2365 // do the test for that character first. We do this in separate passes. The | 2360 // do the test for that character first. We do this in separate passes. The |
2366 // 'preloaded' argument indicates that we are doing such a 'pass'. If such a | 2361 // 'preloaded' argument indicates that we are doing such a 'pass'. If such a |
2367 // pass has been performed then subsequent passes will have true in | 2362 // pass has been performed then subsequent passes will have true in |
2368 // first_element_checked to indicate that that character does not need to be | 2363 // first_element_checked to indicate that that character does not need to be |
2369 // checked again. | 2364 // checked again. |
2370 // | 2365 // |
2371 // In addition to all this we are passed a GenerationVariant, which can | 2366 // In addition to all this we are passed a Trace, which can |
2372 // contain an AlternativeGeneration object. In this AlternativeGeneration | 2367 // contain an AlternativeGeneration object. In this AlternativeGeneration |
2373 // object we can see details of any quick check that was already passed in | 2368 // object we can see details of any quick check that was already passed in |
2374 // order to get to the code we are now generating. The quick check can involve | 2369 // order to get to the code we are now generating. The quick check can involve |
2375 // loading characters, which means we do not need to recheck the bounds | 2370 // loading characters, which means we do not need to recheck the bounds |
2376 // up to the limit the quick check already checked. In addition the quick | 2371 // up to the limit the quick check already checked. In addition the quick |
2377 // check can have involved a mask and compare operation which may simplify | 2372 // check can have involved a mask and compare operation which may simplify |
2378 // or obviate the need for further checks at some character positions. | 2373 // or obviate the need for further checks at some character positions. |
2379 void TextNode::TextEmitPass(RegExpCompiler* compiler, | 2374 void TextNode::TextEmitPass(RegExpCompiler* compiler, |
2380 TextEmitPassType pass, | 2375 TextEmitPassType pass, |
2381 bool preloaded, | 2376 bool preloaded, |
2382 GenerationVariant* variant, | 2377 Trace* trace, |
2383 bool first_element_checked, | 2378 bool first_element_checked, |
2384 int* checked_up_to) { | 2379 int* checked_up_to) { |
2385 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2380 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
2386 bool ascii = compiler->ascii(); | 2381 bool ascii = compiler->ascii(); |
2387 Label* backtrack = variant->backtrack(); | 2382 Label* backtrack = trace->backtrack(); |
2388 QuickCheckDetails* quick_check = variant->quick_check_performed(); | 2383 QuickCheckDetails* quick_check = trace->quick_check_performed(); |
2389 int element_count = elms_->length(); | 2384 int element_count = elms_->length(); |
2390 for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) { | 2385 for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) { |
2391 TextElement elm = elms_->at(i); | 2386 TextElement elm = elms_->at(i); |
2392 int cp_offset = variant->cp_offset() + elm.cp_offset; | 2387 int cp_offset = trace->cp_offset() + elm.cp_offset; |
2393 if (elm.type == TextElement::ATOM) { | 2388 if (elm.type == TextElement::ATOM) { |
2394 if (pass == NON_ASCII_MATCH || | 2389 if (pass == NON_ASCII_MATCH || |
2395 pass == CHARACTER_MATCH || | 2390 pass == CHARACTER_MATCH || |
2396 pass == CASE_CHARACTER_MATCH) { | 2391 pass == CASE_CHARACTER_MATCH) { |
2397 Vector<const uc16> quarks = elm.data.u_atom->data(); | 2392 Vector<const uc16> quarks = elm.data.u_atom->data(); |
2398 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { | 2393 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { |
2399 bool bound_checked = true; // Most ops will check their bounds. | 2394 bool bound_checked = true; // Most ops will check their bounds. |
2400 if (first_element_checked && i == 0 && j == 0) continue; | 2395 if (first_element_checked && i == 0 && j == 0) continue; |
2401 if (quick_check != NULL && | 2396 if (quick_check != NULL && |
2402 elm.cp_offset + j < quick_check->characters() && | 2397 elm.cp_offset + j < quick_check->characters() && |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2479 } | 2474 } |
2480 } | 2475 } |
2481 | 2476 |
2482 | 2477 |
2483 // This generates the code to match a text node. A text node can contain | 2478 // This generates the code to match a text node. A text node can contain |
2484 // straight character sequences (possibly to be matched in a case-independent | 2479 // straight character sequences (possibly to be matched in a case-independent |
2485 // way) and character classes. For efficiency we do not do this in a single | 2480 // way) and character classes. For efficiency we do not do this in a single |
2486 // pass from left to right. Instead we pass over the text node several times, | 2481 // pass from left to right. Instead we pass over the text node several times, |
2487 // emitting code for some character positions every time. See the comment on | 2482 // emitting code for some character positions every time. See the comment on |
2488 // TextEmitPass for details. | 2483 // TextEmitPass for details. |
2489 bool TextNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2484 bool TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
2490 LimitResult limit_result = LimitVersions(compiler, variant); | 2485 LimitResult limit_result = LimitVersions(compiler, trace); |
2491 if (limit_result == FAIL) return false; | 2486 if (limit_result == FAIL) return false; |
2492 if (limit_result == DONE) return true; | 2487 if (limit_result == DONE) return true; |
2493 ASSERT(limit_result == CONTINUE); | 2488 ASSERT(limit_result == CONTINUE); |
2494 | 2489 |
2495 if (info()->follows_word_interest || | 2490 if (info()->follows_word_interest || |
2496 info()->follows_newline_interest || | 2491 info()->follows_newline_interest || |
2497 info()->follows_start_interest) { | 2492 info()->follows_start_interest) { |
2498 return false; | 2493 return false; |
2499 } | 2494 } |
2500 | 2495 |
2501 if (info()->at_end) { | 2496 if (info()->at_end) { |
2502 compiler->macro_assembler()->GoTo(variant->backtrack()); | 2497 compiler->macro_assembler()->GoTo(trace->backtrack()); |
2503 return true; | 2498 return true; |
2504 } | 2499 } |
2505 | 2500 |
2506 if (compiler->ascii()) { | 2501 if (compiler->ascii()) { |
2507 int dummy = 0; | 2502 int dummy = 0; |
2508 TextEmitPass(compiler, NON_ASCII_MATCH, false, variant, false, &dummy); | 2503 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); |
2509 } | 2504 } |
2510 | 2505 |
2511 bool first_elt_done = false; | 2506 bool first_elt_done = false; |
2512 int bound_checked_to = variant->cp_offset() - 1; | 2507 int bound_checked_to = trace->cp_offset() - 1; |
2513 bound_checked_to += variant->bound_checked_up_to(); | 2508 bound_checked_to += trace->bound_checked_up_to(); |
2514 | 2509 |
2515 // If a character is preloaded into the current character register then | 2510 // If a character is preloaded into the current character register then |
2516 // check that now. | 2511 // check that now. |
2517 if (variant->characters_preloaded() == 1) { | 2512 if (trace->characters_preloaded() == 1) { |
2518 TextEmitPass(compiler, | 2513 TextEmitPass(compiler, |
2519 CHARACTER_MATCH, | 2514 CHARACTER_MATCH, |
2520 true, | 2515 true, |
2521 variant, | 2516 trace, |
2522 false, | 2517 false, |
2523 &bound_checked_to); | 2518 &bound_checked_to); |
2524 if (compiler->ignore_case()) { | 2519 if (compiler->ignore_case()) { |
2525 TextEmitPass(compiler, | 2520 TextEmitPass(compiler, |
2526 CASE_CHARACTER_MATCH, | 2521 CASE_CHARACTER_MATCH, |
2527 true, | 2522 true, |
2528 variant, | 2523 trace, |
2529 false, | 2524 false, |
2530 &bound_checked_to); | 2525 &bound_checked_to); |
2531 } | 2526 } |
2532 TextEmitPass(compiler, | 2527 TextEmitPass(compiler, |
2533 CHARACTER_CLASS_MATCH, | 2528 CHARACTER_CLASS_MATCH, |
2534 true, | 2529 true, |
2535 variant, | 2530 trace, |
2536 false, | 2531 false, |
2537 &bound_checked_to); | 2532 &bound_checked_to); |
2538 first_elt_done = true; | 2533 first_elt_done = true; |
2539 } | 2534 } |
2540 | 2535 |
2541 TextEmitPass(compiler, | 2536 TextEmitPass(compiler, |
2542 CHARACTER_MATCH, | 2537 CHARACTER_MATCH, |
2543 false, | 2538 false, |
2544 variant, | 2539 trace, |
2545 first_elt_done, | 2540 first_elt_done, |
2546 &bound_checked_to); | 2541 &bound_checked_to); |
2547 if (compiler->ignore_case()) { | 2542 if (compiler->ignore_case()) { |
2548 TextEmitPass(compiler, | 2543 TextEmitPass(compiler, |
2549 CASE_CHARACTER_MATCH, | 2544 CASE_CHARACTER_MATCH, |
2550 false, | 2545 false, |
2551 variant, | 2546 trace, |
2552 first_elt_done, | 2547 first_elt_done, |
2553 &bound_checked_to); | 2548 &bound_checked_to); |
2554 } | 2549 } |
2555 TextEmitPass(compiler, | 2550 TextEmitPass(compiler, |
2556 CHARACTER_CLASS_MATCH, | 2551 CHARACTER_CLASS_MATCH, |
2557 false, | 2552 false, |
2558 variant, | 2553 trace, |
2559 first_elt_done, | 2554 first_elt_done, |
2560 &bound_checked_to); | 2555 &bound_checked_to); |
2561 | 2556 |
2562 GenerationVariant successor_variant(*variant); | 2557 Trace successor_trace(*trace); |
2563 successor_variant.AdvanceVariant(Length(), compiler->ascii()); | 2558 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler->ascii()); |
2564 RecursionCheck rc(compiler); | 2559 RecursionCheck rc(compiler); |
2565 return on_success()->Emit(compiler, &successor_variant); | 2560 return on_success()->Emit(compiler, &successor_trace); |
2566 } | 2561 } |
2567 | 2562 |
2568 | 2563 |
2569 void GenerationVariant::AdvanceVariant(int by, bool ascii) { | 2564 void Trace::AdvanceCurrentPositionInTrace(int by, bool ascii) { |
2570 ASSERT(by > 0); | 2565 ASSERT(by > 0); |
2571 // We don't have an instruction for shifting the current character register | 2566 // We don't have an instruction for shifting the current character register |
2572 // down or for using a shifted value for anything so lets just forget that | 2567 // down or for using a shifted value for anything so lets just forget that |
2573 // we preloaded any characters into it. | 2568 // we preloaded any characters into it. |
2574 characters_preloaded_ = 0; | 2569 characters_preloaded_ = 0; |
2575 // Adjust the offsets of the quick check performed information. This | 2570 // Adjust the offsets of the quick check performed information. This |
2576 // information is used to find out what we already determined about the | 2571 // information is used to find out what we already determined about the |
2577 // characters by means of mask and compare. | 2572 // characters by means of mask and compare. |
2578 quick_check_performed_.Advance(by, ascii); | 2573 quick_check_performed_.Advance(by, ascii); |
2579 cp_offset_ += by; | 2574 cp_offset_ += by; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2646 } | 2641 } |
2647 | 2642 |
2648 | 2643 |
2649 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { | 2644 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { |
2650 ASSERT_EQ(continue_node_, NULL); | 2645 ASSERT_EQ(continue_node_, NULL); |
2651 AddAlternative(alt); | 2646 AddAlternative(alt); |
2652 continue_node_ = alt.node(); | 2647 continue_node_ = alt.node(); |
2653 } | 2648 } |
2654 | 2649 |
2655 | 2650 |
2656 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, | 2651 bool LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
2657 GenerationVariant* variant) { | |
2658 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2652 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
2659 if (variant->stop_node() == this) { | 2653 if (trace->stop_node() == this) { |
2660 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2654 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
2661 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); | 2655 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); |
2662 // Update the counter-based backtracking info on the stack. This is an | 2656 // Update the counter-based backtracking info on the stack. This is an |
2663 // optimization for greedy loops (see below). | 2657 // optimization for greedy loops (see below). |
2664 ASSERT(variant->cp_offset() == text_length); | 2658 ASSERT(trace->cp_offset() == text_length); |
2665 macro_assembler->AdvanceCurrentPosition(text_length); | 2659 macro_assembler->AdvanceCurrentPosition(text_length); |
2666 macro_assembler->GoTo(variant->loop_label()); | 2660 macro_assembler->GoTo(trace->loop_label()); |
2667 return true; | 2661 return true; |
2668 } | 2662 } |
2669 ASSERT(variant->stop_node() == NULL); | 2663 ASSERT(trace->stop_node() == NULL); |
2670 if (!variant->is_trivial()) { | 2664 if (!trace->is_trivial()) { |
2671 return variant->Flush(compiler, this); | 2665 return trace->Flush(compiler, this); |
2672 } | 2666 } |
2673 return ChoiceNode::Emit(compiler, variant); | 2667 return ChoiceNode::Emit(compiler, trace); |
2674 } | 2668 } |
2675 | 2669 |
2676 | 2670 |
2677 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { | 2671 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { |
2678 int preload_characters = EatsAtLeast(0); | 2672 int preload_characters = EatsAtLeast(0); |
2679 #ifdef CAN_READ_UNALIGNED | 2673 #ifdef CAN_READ_UNALIGNED |
2680 bool ascii = compiler->ascii(); | 2674 bool ascii = compiler->ascii(); |
2681 if (ascii) { | 2675 if (ascii) { |
2682 if (preload_characters > 4) preload_characters = 4; | 2676 if (preload_characters > 4) preload_characters = 4; |
2683 // We can't preload 3 characters because there is no machine instruction | 2677 // We can't preload 3 characters because there is no machine instruction |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2816 * | / | | 2810 * | / | |
2817 * | R | | 2811 * | R | |
2818 * | / | | 2812 * | / | |
2819 * F VL | | 2813 * F VL | |
2820 * <------U | | 2814 * <------U | |
2821 * back |S | | 2815 * back |S | |
2822 * \______________/ | 2816 * \______________/ |
2823 */ | 2817 */ |
2824 | 2818 |
2825 | 2819 |
2826 bool ChoiceNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 2820 bool ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
2827 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2821 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
2828 int choice_count = alternatives_->length(); | 2822 int choice_count = alternatives_->length(); |
2829 #ifdef DEBUG | 2823 #ifdef DEBUG |
2830 for (int i = 0; i < choice_count - 1; i++) { | 2824 for (int i = 0; i < choice_count - 1; i++) { |
2831 GuardedAlternative alternative = alternatives_->at(i); | 2825 GuardedAlternative alternative = alternatives_->at(i); |
2832 ZoneList<Guard*>* guards = alternative.guards(); | 2826 ZoneList<Guard*>* guards = alternative.guards(); |
2833 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2827 int guard_count = (guards == NULL) ? 0 : guards->length(); |
2834 for (int j = 0; j < guard_count; j++) { | 2828 for (int j = 0; j < guard_count; j++) { |
2835 ASSERT(!variant->mentions_reg(guards->at(j)->reg())); | 2829 ASSERT(!trace->mentions_reg(guards->at(j)->reg())); |
2836 } | 2830 } |
2837 } | 2831 } |
2838 #endif | 2832 #endif |
2839 | 2833 |
2840 LimitResult limit_result = LimitVersions(compiler, variant); | 2834 LimitResult limit_result = LimitVersions(compiler, trace); |
2841 if (limit_result == DONE) return true; | 2835 if (limit_result == DONE) return true; |
2842 if (limit_result == FAIL) return false; | 2836 if (limit_result == FAIL) return false; |
2843 ASSERT(limit_result == CONTINUE); | 2837 ASSERT(limit_result == CONTINUE); |
2844 | 2838 |
2845 RecursionCheck rc(compiler); | 2839 RecursionCheck rc(compiler); |
2846 | 2840 |
2847 GenerationVariant* current_variant = variant; | 2841 Trace* current_trace = trace; |
2848 | 2842 |
2849 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); | 2843 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); |
2850 bool greedy_loop = false; | 2844 bool greedy_loop = false; |
2851 Label greedy_loop_label; | 2845 Label greedy_loop_label; |
2852 GenerationVariant counter_backtrack_variant; | 2846 Trace counter_backtrack_trace; |
2853 counter_backtrack_variant.set_backtrack(&greedy_loop_label); | 2847 counter_backtrack_trace.set_backtrack(&greedy_loop_label); |
2854 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { | 2848 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { |
2855 // Here we have special handling for greedy loops containing only text nodes | 2849 // Here we have special handling for greedy loops containing only text nodes |
2856 // and other simple nodes. These are handled by pushing the current | 2850 // and other simple nodes. These are handled by pushing the current |
2857 // position on the stack and then incrementing the current position each | 2851 // position on the stack and then incrementing the current position each |
2858 // time around the switch. On backtrack we decrement the current position | 2852 // time around the switch. On backtrack we decrement the current position |
2859 // and check it against the pushed value. This avoids pushing backtrack | 2853 // and check it against the pushed value. This avoids pushing backtrack |
2860 // information for each iteration of the loop, which could take up a lot of | 2854 // information for each iteration of the loop, which could take up a lot of |
2861 // space. | 2855 // space. |
2862 greedy_loop = true; | 2856 greedy_loop = true; |
2863 ASSERT(variant->stop_node() == NULL); | 2857 ASSERT(trace->stop_node() == NULL); |
2864 macro_assembler->PushCurrentPosition(); | 2858 macro_assembler->PushCurrentPosition(); |
2865 current_variant = &counter_backtrack_variant; | 2859 current_trace = &counter_backtrack_trace; |
2866 Label greedy_match_failed; | 2860 Label greedy_match_failed; |
2867 GenerationVariant greedy_match_variant; | 2861 Trace greedy_match_trace; |
2868 greedy_match_variant.set_backtrack(&greedy_match_failed); | 2862 greedy_match_trace.set_backtrack(&greedy_match_failed); |
2869 Label loop_label; | 2863 Label loop_label; |
2870 macro_assembler->Bind(&loop_label); | 2864 macro_assembler->Bind(&loop_label); |
2871 greedy_match_variant.set_stop_node(this); | 2865 greedy_match_trace.set_stop_node(this); |
2872 greedy_match_variant.set_loop_label(&loop_label); | 2866 greedy_match_trace.set_loop_label(&loop_label); |
2873 bool ok = alternatives_->at(0).node()->Emit(compiler, | 2867 bool ok = alternatives_->at(0).node()->Emit(compiler, |
2874 &greedy_match_variant); | 2868 &greedy_match_trace); |
2875 macro_assembler->Bind(&greedy_match_failed); | 2869 macro_assembler->Bind(&greedy_match_failed); |
2876 if (!ok) { | 2870 if (!ok) { |
2877 greedy_loop_label.Unuse(); | 2871 greedy_loop_label.Unuse(); |
2878 return false; | 2872 return false; |
2879 } | 2873 } |
2880 } | 2874 } |
2881 | 2875 |
2882 Label second_choice; // For use in greedy matches. | 2876 Label second_choice; // For use in greedy matches. |
2883 macro_assembler->Bind(&second_choice); | 2877 macro_assembler->Bind(&second_choice); |
2884 | 2878 |
2885 int first_normal_choice = greedy_loop ? 1 : 0; | 2879 int first_normal_choice = greedy_loop ? 1 : 0; |
2886 | 2880 |
2887 int preload_characters = CalculatePreloadCharacters(compiler); | 2881 int preload_characters = CalculatePreloadCharacters(compiler); |
2888 bool preload_is_current = | 2882 bool preload_is_current = |
2889 (current_variant->characters_preloaded() == preload_characters); | 2883 (current_trace->characters_preloaded() == preload_characters); |
2890 bool preload_has_checked_bounds = preload_is_current; | 2884 bool preload_has_checked_bounds = preload_is_current; |
2891 | 2885 |
2892 AlternativeGenerationList alt_gens(choice_count); | 2886 AlternativeGenerationList alt_gens(choice_count); |
2893 | 2887 |
2894 // For now we just call all choices one after the other. The idea ultimately | 2888 // For now we just call all choices one after the other. The idea ultimately |
2895 // is to use the Dispatch table to try only the relevant ones. | 2889 // is to use the Dispatch table to try only the relevant ones. |
2896 for (int i = first_normal_choice; i < choice_count; i++) { | 2890 for (int i = first_normal_choice; i < choice_count; i++) { |
2897 GuardedAlternative alternative = alternatives_->at(i); | 2891 GuardedAlternative alternative = alternatives_->at(i); |
2898 AlternativeGeneration* alt_gen = alt_gens.at(i); | 2892 AlternativeGeneration* alt_gen = alt_gens.at(i); |
2899 alt_gen->quick_check_details.set_characters(preload_characters); | 2893 alt_gen->quick_check_details.set_characters(preload_characters); |
2900 ZoneList<Guard*>* guards = alternative.guards(); | 2894 ZoneList<Guard*>* guards = alternative.guards(); |
2901 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2895 int guard_count = (guards == NULL) ? 0 : guards->length(); |
2902 GenerationVariant new_variant(*current_variant); | 2896 Trace new_trace(*current_trace); |
2903 new_variant.set_characters_preloaded(preload_is_current ? | 2897 new_trace.set_characters_preloaded(preload_is_current ? |
2904 preload_characters : | 2898 preload_characters : |
2905 0); | 2899 0); |
2906 if (preload_has_checked_bounds) { | 2900 if (preload_has_checked_bounds) { |
2907 new_variant.set_bound_checked_up_to(preload_characters); | 2901 new_trace.set_bound_checked_up_to(preload_characters); |
2908 } | 2902 } |
2909 new_variant.quick_check_performed()->Clear(); | 2903 new_trace.quick_check_performed()->Clear(); |
2910 alt_gen->expects_preload = preload_is_current; | 2904 alt_gen->expects_preload = preload_is_current; |
2911 bool generate_full_check_inline = false; | 2905 bool generate_full_check_inline = false; |
2912 if (alternative.node()->EmitQuickCheck(compiler, | 2906 if (alternative.node()->EmitQuickCheck(compiler, |
2913 &new_variant, | 2907 &new_trace, |
2914 preload_has_checked_bounds, | 2908 preload_has_checked_bounds, |
2915 &alt_gen->possible_success, | 2909 &alt_gen->possible_success, |
2916 &alt_gen->quick_check_details, | 2910 &alt_gen->quick_check_details, |
2917 i < choice_count - 1)) { | 2911 i < choice_count - 1)) { |
2918 // Quick check was generated for this choice. | 2912 // Quick check was generated for this choice. |
2919 preload_is_current = true; | 2913 preload_is_current = true; |
2920 preload_has_checked_bounds = true; | 2914 preload_has_checked_bounds = true; |
2921 // On the last choice in the ChoiceNode we generated the quick | 2915 // On the last choice in the ChoiceNode we generated the quick |
2922 // check to fall through on possible success. So now we need to | 2916 // check to fall through on possible success. So now we need to |
2923 // generate the full check inline. | 2917 // generate the full check inline. |
2924 if (i == choice_count - 1) { | 2918 if (i == choice_count - 1) { |
2925 macro_assembler->Bind(&alt_gen->possible_success); | 2919 macro_assembler->Bind(&alt_gen->possible_success); |
2926 new_variant.set_quick_check_performed(&alt_gen->quick_check_details); | 2920 new_trace.set_quick_check_performed(&alt_gen->quick_check_details); |
2927 new_variant.set_characters_preloaded(preload_characters); | 2921 new_trace.set_characters_preloaded(preload_characters); |
2928 new_variant.set_bound_checked_up_to(preload_characters); | 2922 new_trace.set_bound_checked_up_to(preload_characters); |
2929 generate_full_check_inline = true; | 2923 generate_full_check_inline = true; |
2930 } | 2924 } |
2931 } else { | 2925 } else { |
2932 // No quick check was generated. Put the full code here. | 2926 // No quick check was generated. Put the full code here. |
2933 // If this is not the first choice then there could be slow checks from | 2927 // If this is not the first choice then there could be slow checks from |
2934 // previous cases that go here when they fail. There's no reason to | 2928 // previous cases that go here when they fail. There's no reason to |
2935 // insist that they preload characters since the slow check we are about | 2929 // insist that they preload characters since the slow check we are about |
2936 // to generate probably can't use it. | 2930 // to generate probably can't use it. |
2937 if (i != first_normal_choice) { | 2931 if (i != first_normal_choice) { |
2938 alt_gen->expects_preload = false; | 2932 alt_gen->expects_preload = false; |
2939 new_variant.set_characters_preloaded(0); | 2933 new_trace.set_characters_preloaded(0); |
2940 } | 2934 } |
2941 if (i < choice_count - 1) { | 2935 if (i < choice_count - 1) { |
2942 new_variant.set_backtrack(&alt_gen->after); | 2936 new_trace.set_backtrack(&alt_gen->after); |
2943 } | 2937 } |
2944 generate_full_check_inline = true; | 2938 generate_full_check_inline = true; |
2945 } | 2939 } |
2946 if (generate_full_check_inline) { | 2940 if (generate_full_check_inline) { |
2947 for (int j = 0; j < guard_count; j++) { | 2941 for (int j = 0; j < guard_count; j++) { |
2948 GenerateGuard(macro_assembler, guards->at(j), &new_variant); | 2942 GenerateGuard(macro_assembler, guards->at(j), &new_trace); |
2949 } | 2943 } |
2950 if (!alternative.node()->Emit(compiler, &new_variant)) { | 2944 if (!alternative.node()->Emit(compiler, &new_trace)) { |
2951 greedy_loop_label.Unuse(); | 2945 greedy_loop_label.Unuse(); |
2952 return false; | 2946 return false; |
2953 } | 2947 } |
2954 preload_is_current = false; | 2948 preload_is_current = false; |
2955 } | 2949 } |
2956 macro_assembler->Bind(&alt_gen->after); | 2950 macro_assembler->Bind(&alt_gen->after); |
2957 } | 2951 } |
2958 if (greedy_loop) { | 2952 if (greedy_loop) { |
2959 macro_assembler->Bind(&greedy_loop_label); | 2953 macro_assembler->Bind(&greedy_loop_label); |
2960 // If we have unwound to the bottom then backtrack. | 2954 // If we have unwound to the bottom then backtrack. |
2961 macro_assembler->CheckGreedyLoop(variant->backtrack()); | 2955 macro_assembler->CheckGreedyLoop(trace->backtrack()); |
2962 // Otherwise try the second priority at an earlier position. | 2956 // Otherwise try the second priority at an earlier position. |
2963 macro_assembler->AdvanceCurrentPosition(-text_length); | 2957 macro_assembler->AdvanceCurrentPosition(-text_length); |
2964 macro_assembler->GoTo(&second_choice); | 2958 macro_assembler->GoTo(&second_choice); |
2965 } | 2959 } |
2966 // At this point we need to generate slow checks for the alternatives where | 2960 // At this point we need to generate slow checks for the alternatives where |
2967 // the quick check was inlined. We can recognize these because the associated | 2961 // the quick check was inlined. We can recognize these because the associated |
2968 // label was bound. | 2962 // label was bound. |
2969 for (int i = first_normal_choice; i < choice_count - 1; i++) { | 2963 for (int i = first_normal_choice; i < choice_count - 1; i++) { |
2970 AlternativeGeneration* alt_gen = alt_gens.at(i); | 2964 AlternativeGeneration* alt_gen = alt_gens.at(i); |
2971 if (!EmitOutOfLineContinuation(compiler, | 2965 if (!EmitOutOfLineContinuation(compiler, |
2972 current_variant, | 2966 current_trace, |
2973 alternatives_->at(i), | 2967 alternatives_->at(i), |
2974 alt_gen, | 2968 alt_gen, |
2975 preload_characters, | 2969 preload_characters, |
2976 alt_gens.at(i + 1)->expects_preload)) { | 2970 alt_gens.at(i + 1)->expects_preload)) { |
2977 return false; | 2971 return false; |
2978 } | 2972 } |
2979 } | 2973 } |
2980 return true; | 2974 return true; |
2981 } | 2975 } |
2982 | 2976 |
2983 | 2977 |
2984 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, | 2978 bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, |
2985 GenerationVariant* variant, | 2979 Trace* trace, |
2986 GuardedAlternative alternative, | 2980 GuardedAlternative alternative, |
2987 AlternativeGeneration* alt_gen, | 2981 AlternativeGeneration* alt_gen, |
2988 int preload_characters, | 2982 int preload_characters, |
2989 bool next_expects_preload) { | 2983 bool next_expects_preload) { |
2990 if (!alt_gen->possible_success.is_linked()) return true; | 2984 if (!alt_gen->possible_success.is_linked()) return true; |
2991 | 2985 |
2992 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 2986 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
2993 macro_assembler->Bind(&alt_gen->possible_success); | 2987 macro_assembler->Bind(&alt_gen->possible_success); |
2994 GenerationVariant out_of_line_variant(*variant); | 2988 Trace out_of_line_trace(*trace); |
2995 out_of_line_variant.set_characters_preloaded(preload_characters); | 2989 out_of_line_trace.set_characters_preloaded(preload_characters); |
2996 out_of_line_variant.set_quick_check_performed(&alt_gen->quick_check_details); | 2990 out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details); |
2997 ZoneList<Guard*>* guards = alternative.guards(); | 2991 ZoneList<Guard*>* guards = alternative.guards(); |
2998 int guard_count = (guards == NULL) ? 0 : guards->length(); | 2992 int guard_count = (guards == NULL) ? 0 : guards->length(); |
2999 if (next_expects_preload) { | 2993 if (next_expects_preload) { |
3000 Label reload_current_char; | 2994 Label reload_current_char; |
3001 out_of_line_variant.set_backtrack(&reload_current_char); | 2995 out_of_line_trace.set_backtrack(&reload_current_char); |
3002 for (int j = 0; j < guard_count; j++) { | 2996 for (int j = 0; j < guard_count; j++) { |
3003 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); | 2997 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
3004 } | 2998 } |
3005 bool ok = alternative.node()->Emit(compiler, &out_of_line_variant); | 2999 bool ok = alternative.node()->Emit(compiler, &out_of_line_trace); |
3006 macro_assembler->Bind(&reload_current_char); | 3000 macro_assembler->Bind(&reload_current_char); |
3007 // Reload the current character, since the next quick check expects that. | 3001 // Reload the current character, since the next quick check expects that. |
3008 // We don't need to check bounds here because we only get into this | 3002 // We don't need to check bounds here because we only get into this |
3009 // code through a quick check which already did the checked load. | 3003 // code through a quick check which already did the checked load. |
3010 macro_assembler->LoadCurrentCharacter(variant->cp_offset(), | 3004 macro_assembler->LoadCurrentCharacter(trace->cp_offset(), |
3011 NULL, | 3005 NULL, |
3012 false, | 3006 false, |
3013 preload_characters); | 3007 preload_characters); |
3014 macro_assembler->GoTo(&(alt_gen->after)); | 3008 macro_assembler->GoTo(&(alt_gen->after)); |
3015 return ok; | 3009 return ok; |
3016 } else { | 3010 } else { |
3017 out_of_line_variant.set_backtrack(&(alt_gen->after)); | 3011 out_of_line_trace.set_backtrack(&(alt_gen->after)); |
3018 for (int j = 0; j < guard_count; j++) { | 3012 for (int j = 0; j < guard_count; j++) { |
3019 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_variant); | 3013 GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace); |
3020 } | 3014 } |
3021 return alternative.node()->Emit(compiler, &out_of_line_variant); | 3015 return alternative.node()->Emit(compiler, &out_of_line_trace); |
3022 } | 3016 } |
3023 } | 3017 } |
3024 | 3018 |
3025 | 3019 |
3026 bool ActionNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) { | 3020 bool ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
3027 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3021 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
3028 LimitResult limit_result = LimitVersions(compiler, variant); | 3022 LimitResult limit_result = LimitVersions(compiler, trace); |
3029 if (limit_result == DONE) return true; | 3023 if (limit_result == DONE) return true; |
3030 if (limit_result == FAIL) return false; | 3024 if (limit_result == FAIL) return false; |
3031 ASSERT(limit_result == CONTINUE); | 3025 ASSERT(limit_result == CONTINUE); |
3032 | 3026 |
3033 RecursionCheck rc(compiler); | 3027 RecursionCheck rc(compiler); |
3034 | 3028 |
3035 switch (type_) { | 3029 switch (type_) { |
3036 case STORE_POSITION: { | 3030 case STORE_POSITION: { |
3037 GenerationVariant::DeferredCapture | 3031 Trace::DeferredCapture |
3038 new_capture(data_.u_position_register.reg, variant); | 3032 new_capture(data_.u_position_register.reg, trace); |
3039 GenerationVariant new_variant = *variant; | 3033 Trace new_trace = *trace; |
3040 new_variant.add_action(&new_capture); | 3034 new_trace.add_action(&new_capture); |
3041 return on_success()->Emit(compiler, &new_variant); | 3035 return on_success()->Emit(compiler, &new_trace); |
3042 } | 3036 } |
3043 case INCREMENT_REGISTER: { | 3037 case INCREMENT_REGISTER: { |
3044 GenerationVariant::DeferredIncrementRegister | 3038 Trace::DeferredIncrementRegister |
3045 new_increment(data_.u_increment_register.reg); | 3039 new_increment(data_.u_increment_register.reg); |
3046 GenerationVariant new_variant = *variant; | 3040 Trace new_trace = *trace; |
3047 new_variant.add_action(&new_increment); | 3041 new_trace.add_action(&new_increment); |
3048 return on_success()->Emit(compiler, &new_variant); | 3042 return on_success()->Emit(compiler, &new_trace); |
3049 } | 3043 } |
3050 case SET_REGISTER: { | 3044 case SET_REGISTER: { |
3051 GenerationVariant::DeferredSetRegister | 3045 Trace::DeferredSetRegister |
3052 new_set(data_.u_store_register.reg, data_.u_store_register.value); | 3046 new_set(data_.u_store_register.reg, data_.u_store_register.value); |
3053 GenerationVariant new_variant = *variant; | 3047 Trace new_trace = *trace; |
3054 new_variant.add_action(&new_set); | 3048 new_trace.add_action(&new_set); |
3055 return on_success()->Emit(compiler, &new_variant); | 3049 return on_success()->Emit(compiler, &new_trace); |
3056 } | 3050 } |
3057 case CLEAR_CAPTURES: { | 3051 case CLEAR_CAPTURES: { |
3058 GenerationVariant::DeferredClearCaptures | 3052 Trace::DeferredClearCaptures |
3059 new_capture(Interval(data_.u_clear_captures.range_from, | 3053 new_capture(Interval(data_.u_clear_captures.range_from, |
3060 data_.u_clear_captures.range_to)); | 3054 data_.u_clear_captures.range_to)); |
3061 GenerationVariant new_variant = *variant; | 3055 Trace new_trace = *trace; |
3062 new_variant.add_action(&new_capture); | 3056 new_trace.add_action(&new_capture); |
3063 return on_success()->Emit(compiler, &new_variant); | 3057 return on_success()->Emit(compiler, &new_trace); |
3064 } | 3058 } |
3065 case BEGIN_SUBMATCH: | 3059 case BEGIN_SUBMATCH: |
3066 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 3060 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
3067 assembler->WriteCurrentPositionToRegister( | 3061 assembler->WriteCurrentPositionToRegister( |
3068 data_.u_submatch.current_position_register, 0); | 3062 data_.u_submatch.current_position_register, 0); |
3069 assembler->WriteStackPointerToRegister( | 3063 assembler->WriteStackPointerToRegister( |
3070 data_.u_submatch.stack_pointer_register); | 3064 data_.u_submatch.stack_pointer_register); |
3071 return on_success()->Emit(compiler, variant); | 3065 return on_success()->Emit(compiler, trace); |
3072 case EMPTY_MATCH_CHECK: { | 3066 case EMPTY_MATCH_CHECK: { |
3073 int start_pos_reg = data_.u_empty_match_check.start_register; | 3067 int start_pos_reg = data_.u_empty_match_check.start_register; |
3074 int stored_pos = 0; | 3068 int stored_pos = 0; |
3075 int rep_reg = data_.u_empty_match_check.repetition_register; | 3069 int rep_reg = data_.u_empty_match_check.repetition_register; |
3076 bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister); | 3070 bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister); |
3077 bool know_dist = variant->GetStoredPosition(start_pos_reg, &stored_pos); | 3071 bool know_dist = trace->GetStoredPosition(start_pos_reg, &stored_pos); |
3078 if (know_dist && !has_minimum && stored_pos == variant->cp_offset()) { | 3072 if (know_dist && !has_minimum && stored_pos == trace->cp_offset()) { |
3079 // If we know we haven't advanced and there is no minimum we | 3073 // If we know we haven't advanced and there is no minimum we |
3080 // can just backtrack immediately. | 3074 // can just backtrack immediately. |
3081 assembler->GoTo(variant->backtrack()); | 3075 assembler->GoTo(trace->backtrack()); |
3082 return true; | 3076 return true; |
3083 } else if (know_dist && stored_pos < variant->cp_offset()) { | 3077 } else if (know_dist && stored_pos < trace->cp_offset()) { |
3084 // If we know we've advanced we can generate the continuation | 3078 // If we know we've advanced we can generate the continuation |
3085 // immediately. | 3079 // immediately. |
3086 return on_success()->Emit(compiler, variant); | 3080 return on_success()->Emit(compiler, trace); |
3087 } | 3081 } |
3088 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 3082 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
3089 Label skip_empty_check; | 3083 Label skip_empty_check; |
3090 // If we have a minimum number of repetitions we check the current | 3084 // If we have a minimum number of repetitions we check the current |
3091 // number first and skip the empty check if it's not enough. | 3085 // number first and skip the empty check if it's not enough. |
3092 if (has_minimum) { | 3086 if (has_minimum) { |
3093 int limit = data_.u_empty_match_check.repetition_limit; | 3087 int limit = data_.u_empty_match_check.repetition_limit; |
3094 assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check); | 3088 assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check); |
3095 } | 3089 } |
3096 // If the match is empty we bail out, otherwise we fall through | 3090 // If the match is empty we bail out, otherwise we fall through |
3097 // to the on-success continuation. | 3091 // to the on-success continuation. |
3098 assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register, | 3092 assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register, |
3099 variant->backtrack()); | 3093 trace->backtrack()); |
3100 assembler->Bind(&skip_empty_check); | 3094 assembler->Bind(&skip_empty_check); |
3101 return on_success()->Emit(compiler, variant); | 3095 return on_success()->Emit(compiler, trace); |
3102 } | 3096 } |
3103 case POSITIVE_SUBMATCH_SUCCESS: | 3097 case POSITIVE_SUBMATCH_SUCCESS: |
3104 if (!variant->is_trivial()) return variant->Flush(compiler, this); | 3098 if (!trace->is_trivial()) return trace->Flush(compiler, this); |
3105 // TODO(erikcorry): Implement support. | 3099 // TODO(erikcorry): Implement support. |
3106 if (info()->follows_word_interest || | 3100 if (info()->follows_word_interest || |
3107 info()->follows_newline_interest || | 3101 info()->follows_newline_interest || |
3108 info()->follows_start_interest) { | 3102 info()->follows_start_interest) { |
3109 return false; | 3103 return false; |
3110 } | 3104 } |
3111 if (info()->at_end) { | 3105 if (info()->at_end) { |
3112 Label at_end; | 3106 Label at_end; |
3113 // Load current character jumps to the label if we are beyond the string | 3107 // Load current character jumps to the label if we are beyond the string |
3114 // end. | 3108 // end. |
3115 assembler->LoadCurrentCharacter(0, &at_end); | 3109 assembler->LoadCurrentCharacter(0, &at_end); |
3116 assembler->GoTo(variant->backtrack()); | 3110 assembler->GoTo(trace->backtrack()); |
3117 assembler->Bind(&at_end); | 3111 assembler->Bind(&at_end); |
3118 } | 3112 } |
3119 assembler->ReadCurrentPositionFromRegister( | 3113 assembler->ReadCurrentPositionFromRegister( |
3120 data_.u_submatch.current_position_register); | 3114 data_.u_submatch.current_position_register); |
3121 assembler->ReadStackPointerFromRegister( | 3115 assembler->ReadStackPointerFromRegister( |
3122 data_.u_submatch.stack_pointer_register); | 3116 data_.u_submatch.stack_pointer_register); |
3123 return on_success()->Emit(compiler, variant); | 3117 return on_success()->Emit(compiler, trace); |
3124 default: | 3118 default: |
3125 UNREACHABLE(); | 3119 UNREACHABLE(); |
3126 return false; | 3120 return false; |
3127 } | 3121 } |
3128 } | 3122 } |
3129 | 3123 |
3130 | 3124 |
3131 bool BackReferenceNode::Emit(RegExpCompiler* compiler, | 3125 bool BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
3132 GenerationVariant* variant) { | |
3133 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3126 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
3134 if (!variant->is_trivial()) { | 3127 if (!trace->is_trivial()) { |
3135 return variant->Flush(compiler, this); | 3128 return trace->Flush(compiler, this); |
3136 } | 3129 } |
3137 | 3130 |
3138 LimitResult limit_result = LimitVersions(compiler, variant); | 3131 LimitResult limit_result = LimitVersions(compiler, trace); |
3139 if (limit_result == DONE) return true; | 3132 if (limit_result == DONE) return true; |
3140 if (limit_result == FAIL) return false; | 3133 if (limit_result == FAIL) return false; |
3141 ASSERT(limit_result == CONTINUE); | 3134 ASSERT(limit_result == CONTINUE); |
3142 | 3135 |
3143 RecursionCheck rc(compiler); | 3136 RecursionCheck rc(compiler); |
3144 | 3137 |
3145 ASSERT_EQ(start_reg_ + 1, end_reg_); | 3138 ASSERT_EQ(start_reg_ + 1, end_reg_); |
3146 if (info()->at_end) { | 3139 if (info()->at_end) { |
3147 // If we are constrained to match at the end of the input then succeed | 3140 // If we are constrained to match at the end of the input then succeed |
3148 // iff the back reference is empty. | 3141 // iff the back reference is empty. |
3149 assembler->CheckNotRegistersEqual(start_reg_, | 3142 assembler->CheckNotRegistersEqual(start_reg_, |
3150 end_reg_, | 3143 end_reg_, |
3151 variant->backtrack()); | 3144 trace->backtrack()); |
3152 } else { | 3145 } else { |
3153 if (compiler->ignore_case()) { | 3146 if (compiler->ignore_case()) { |
3154 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, | 3147 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, |
3155 variant->backtrack()); | 3148 trace->backtrack()); |
3156 } else { | 3149 } else { |
3157 assembler->CheckNotBackReference(start_reg_, variant->backtrack()); | 3150 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); |
3158 } | 3151 } |
3159 } | 3152 } |
3160 return on_success()->Emit(compiler, variant); | 3153 return on_success()->Emit(compiler, trace); |
3161 } | 3154 } |
3162 | 3155 |
3163 | 3156 |
3164 // ------------------------------------------------------------------- | 3157 // ------------------------------------------------------------------- |
3165 // Dot/dotty output | 3158 // Dot/dotty output |
3166 | 3159 |
3167 | 3160 |
3168 #ifdef DEBUG | 3161 #ifdef DEBUG |
3169 | 3162 |
3170 | 3163 |
(...skipping 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4559 EmbeddedVector<byte, 1024> codes; | 4552 EmbeddedVector<byte, 1024> codes; |
4560 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4553 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
4561 return compiler.Assemble(¯o_assembler, | 4554 return compiler.Assemble(¯o_assembler, |
4562 node, | 4555 node, |
4563 data->capture_count, | 4556 data->capture_count, |
4564 pattern); | 4557 pattern); |
4565 } | 4558 } |
4566 | 4559 |
4567 | 4560 |
4568 }} // namespace v8::internal | 4561 }} // namespace v8::internal |
OLD | NEW |