| 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 |