| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_MIPS64 | 5 #if V8_TARGET_ARCH_MIPS64 |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 1249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1260 // Restore callee-saved fpu registers. | 1260 // Restore callee-saved fpu registers. |
| 1261 __ MultiPopFPU(kCalleeSavedFPU); | 1261 __ MultiPopFPU(kCalleeSavedFPU); |
| 1262 | 1262 |
| 1263 // Restore callee saved registers from the stack. | 1263 // Restore callee saved registers from the stack. |
| 1264 __ MultiPop(kCalleeSaved | ra.bit()); | 1264 __ MultiPop(kCalleeSaved | ra.bit()); |
| 1265 // Return. | 1265 // Return. |
| 1266 __ Jump(ra); | 1266 __ Jump(ra); |
| 1267 } | 1267 } |
| 1268 | 1268 |
| 1269 void RegExpExecStub::Generate(MacroAssembler* masm) { | 1269 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 1270 // Just jump directly to runtime if native RegExp is not selected at compile | |
| 1271 // time or if regexp entry in generated code is turned off runtime switch or | |
| 1272 // at compilation. | |
| 1273 #ifdef V8_INTERPRETED_REGEXP | 1270 #ifdef V8_INTERPRETED_REGEXP |
| 1274 __ TailCallRuntime(Runtime::kRegExpExec); | 1271 // This case is handled prior to the RegExpExecStub call. |
| 1272 __ Abort(kUnexpectedRegExpExecCall); |
| 1275 #else // V8_INTERPRETED_REGEXP | 1273 #else // V8_INTERPRETED_REGEXP |
| 1276 | |
| 1277 // Stack frame on entry. | |
| 1278 // sp[0]: last_match_info (expected JSArray) | |
| 1279 // sp[4]: previous index | |
| 1280 // sp[8]: subject string | |
| 1281 // sp[12]: JSRegExp object | |
| 1282 | |
| 1283 const int kLastMatchInfoOffset = 0 * kPointerSize; | |
| 1284 const int kPreviousIndexOffset = 1 * kPointerSize; | |
| 1285 const int kSubjectOffset = 2 * kPointerSize; | |
| 1286 const int kJSRegExpOffset = 3 * kPointerSize; | |
| 1287 | |
| 1288 Label runtime; | |
| 1289 // Allocation of registers for this function. These are in callee save | |
| 1290 // registers and will be preserved by the call to the native RegExp code, as | |
| 1291 // this code is called using the normal C calling convention. When calling | |
| 1292 // directly from generated code the native RegExp code will not do a GC and | |
| 1293 // therefore the content of these registers are safe to use after the call. | |
| 1294 // MIPS - using s0..s2, since we are not using CEntry Stub. | |
| 1295 Register subject = s0; | |
| 1296 Register regexp_data = s1; | |
| 1297 Register last_match_info_elements = s2; | |
| 1298 | |
| 1299 // Ensure that a RegExp stack is allocated. | |
| 1300 ExternalReference address_of_regexp_stack_memory_address = | |
| 1301 ExternalReference::address_of_regexp_stack_memory_address( | |
| 1302 isolate()); | |
| 1303 ExternalReference address_of_regexp_stack_memory_size = | |
| 1304 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
| 1305 __ li(a0, Operand(address_of_regexp_stack_memory_size)); | |
| 1306 __ ld(a0, MemOperand(a0, 0)); | |
| 1307 __ Branch(&runtime, eq, a0, Operand(zero_reg)); | |
| 1308 | |
| 1309 // Check that the first argument is a JSRegExp object. | |
| 1310 __ ld(a0, MemOperand(sp, kJSRegExpOffset)); | |
| 1311 STATIC_ASSERT(kSmiTag == 0); | |
| 1312 __ JumpIfSmi(a0, &runtime); | |
| 1313 __ GetObjectType(a0, a1, a1); | |
| 1314 __ Branch(&runtime, ne, a1, Operand(JS_REGEXP_TYPE)); | |
| 1315 | |
| 1316 // Check that the RegExp has been compiled (data contains a fixed array). | |
| 1317 __ ld(regexp_data, FieldMemOperand(a0, JSRegExp::kDataOffset)); | |
| 1318 if (FLAG_debug_code) { | |
| 1319 __ SmiTst(regexp_data, a4); | |
| 1320 __ Check(nz, | |
| 1321 kUnexpectedTypeForRegExpDataFixedArrayExpected, | |
| 1322 a4, | |
| 1323 Operand(zero_reg)); | |
| 1324 __ GetObjectType(regexp_data, a0, a0); | |
| 1325 __ Check(eq, | |
| 1326 kUnexpectedTypeForRegExpDataFixedArrayExpected, | |
| 1327 a0, | |
| 1328 Operand(FIXED_ARRAY_TYPE)); | |
| 1329 } | |
| 1330 | |
| 1331 // regexp_data: RegExp data (FixedArray) | |
| 1332 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
| 1333 __ ld(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | |
| 1334 __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | |
| 1335 | |
| 1336 // regexp_data: RegExp data (FixedArray) | |
| 1337 // Check that the number of captures fit in the static offsets vector buffer. | |
| 1338 __ ld(a2, | |
| 1339 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | |
| 1340 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
| 1341 // Or number_of_captures * 2 <= offsets vector size - 2 | |
| 1342 // Or number_of_captures <= offsets vector size / 2 - 1 | |
| 1343 // Multiplying by 2 comes for free since a2 is smi-tagged. | |
| 1344 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
| 1345 int temp = Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1; | |
| 1346 __ Branch(&runtime, hi, a2, Operand(Smi::FromInt(temp))); | |
| 1347 | |
| 1348 // Reset offset for possibly sliced string. | |
| 1349 __ mov(t0, zero_reg); | |
| 1350 __ ld(subject, MemOperand(sp, kSubjectOffset)); | |
| 1351 __ JumpIfSmi(subject, &runtime); | |
| 1352 __ mov(a3, subject); // Make a copy of the original subject string. | |
| 1353 | |
| 1354 // subject: subject string | |
| 1355 // a3: subject string | |
| 1356 // regexp_data: RegExp data (FixedArray) | |
| 1357 // Handle subject string according to its encoding and representation: | |
| 1358 // (1) Sequential string? If yes, go to (4). | |
| 1359 // (2) Sequential or cons? If not, go to (5). | |
| 1360 // (3) Cons string. If the string is flat, replace subject with first string | |
| 1361 // and go to (1). Otherwise bail out to runtime. | |
| 1362 // (4) Sequential string. Load regexp code according to encoding. | |
| 1363 // (E) Carry on. | |
| 1364 /// [...] | |
| 1365 | |
| 1366 // Deferred code at the end of the stub: | |
| 1367 // (5) Long external string? If not, go to (7). | |
| 1368 // (6) External string. Make it, offset-wise, look like a sequential string. | |
| 1369 // Go to (4). | |
| 1370 // (7) Short external string or not a string? If yes, bail out to runtime. | |
| 1371 // (8) Sliced or thin string. Replace subject with parent. Go to (1). | |
| 1372 | |
| 1373 Label check_underlying; // (1) | |
| 1374 Label seq_string; // (4) | |
| 1375 Label not_seq_nor_cons; // (5) | |
| 1376 Label external_string; // (6) | |
| 1377 Label not_long_external; // (7) | |
| 1378 | |
| 1379 __ bind(&check_underlying); | |
| 1380 __ ld(a2, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
| 1381 __ lbu(a0, FieldMemOperand(a2, Map::kInstanceTypeOffset)); | |
| 1382 | |
| 1383 // (1) Sequential string? If yes, go to (4). | |
| 1384 __ And(a1, | |
| 1385 a0, | |
| 1386 Operand(kIsNotStringMask | | |
| 1387 kStringRepresentationMask | | |
| 1388 kShortExternalStringMask)); | |
| 1389 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | |
| 1390 __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // Go to (4). | |
| 1391 | |
| 1392 // (2) Sequential or cons? If not, go to (5). | |
| 1393 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
| 1394 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
| 1395 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
| 1396 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
| 1397 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
| 1398 // Go to (5). | |
| 1399 __ Branch(¬_seq_nor_cons, ge, a1, Operand(kExternalStringTag)); | |
| 1400 | |
| 1401 // (3) Cons string. Check that it's flat. | |
| 1402 // Replace subject with first string and reload instance type. | |
| 1403 __ ld(a0, FieldMemOperand(subject, ConsString::kSecondOffset)); | |
| 1404 __ LoadRoot(a1, Heap::kempty_stringRootIndex); | |
| 1405 __ Branch(&runtime, ne, a0, Operand(a1)); | |
| 1406 __ ld(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | |
| 1407 __ jmp(&check_underlying); | |
| 1408 | |
| 1409 // (4) Sequential string. Load regexp code according to encoding. | |
| 1410 __ bind(&seq_string); | |
| 1411 // subject: sequential subject string (or look-alike, external string) | |
| 1412 // a3: original subject string | |
| 1413 // Load previous index and check range before a3 is overwritten. We have to | |
| 1414 // use a3 instead of subject here because subject might have been only made | |
| 1415 // to look like a sequential string when it actually is an external string. | |
| 1416 __ ld(a1, MemOperand(sp, kPreviousIndexOffset)); | |
| 1417 __ JumpIfNotSmi(a1, &runtime); | |
| 1418 __ ld(a3, FieldMemOperand(a3, String::kLengthOffset)); | |
| 1419 __ Branch(&runtime, ls, a3, Operand(a1)); | |
| 1420 __ SmiUntag(a1); | |
| 1421 | |
| 1422 STATIC_ASSERT(kStringEncodingMask == 8); | |
| 1423 STATIC_ASSERT(kOneByteStringTag == 8); | |
| 1424 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 1425 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for one_byte. | |
| 1426 __ ld(t9, FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset)); | |
| 1427 __ dsra(a3, a0, 3); // a3 is 1 for one_byte, 0 for UC16 (used below). | |
| 1428 __ ld(a5, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); | |
| 1429 __ Movz(t9, a5, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. | |
| 1430 | |
| 1431 // (E) Carry on. String handling is done. | |
| 1432 // t9: irregexp code | |
| 1433 // Check that the irregexp code has been generated for the actual string | |
| 1434 // encoding. If it has, the field contains a code object otherwise it contains | |
| 1435 // a smi (code flushing support). | |
| 1436 __ JumpIfSmi(t9, &runtime); | |
| 1437 | |
| 1438 // a1: previous index | |
| 1439 // a3: encoding of subject string (1 if one_byte, 0 if two_byte); | |
| 1440 // t9: code | |
| 1441 // subject: Subject string | |
| 1442 // regexp_data: RegExp data (FixedArray) | |
| 1443 // All checks done. Now push arguments for native regexp code. | |
| 1444 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), | |
| 1445 1, a0, a2); | |
| 1446 | |
| 1447 // Isolates: note we add an additional parameter here (isolate pointer). | 1274 // Isolates: note we add an additional parameter here (isolate pointer). |
| 1448 const int kRegExpExecuteArguments = 9; | 1275 const int kRegExpExecuteArguments = 9; |
| 1449 const int kParameterRegisters = 8; | 1276 const int kParameterRegisters = 8; |
| 1450 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); | 1277 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); |
| 1451 | 1278 |
| 1452 // Stack pointer now points to cell where return address is to be written. | 1279 // Stack pointer now points to cell where return address is to be written. |
| 1453 // Arguments are before that on the stack or in registers, meaning we | 1280 // Arguments are before that on the stack or in registers, meaning we |
| 1454 // treat the return address as argument 5. Thus every argument after that | 1281 // treat the return address as argument 5. Thus every argument after that |
| 1455 // needs to be shifted back by 1. Since DirectCEntryStub will handle | 1282 // needs to be shifted back by 1. Since DirectCEntryStub will handle |
| 1456 // allocating space for the c argument slots, we don't need to calculate | 1283 // allocating space for the c argument slots, we don't need to calculate |
| 1457 // that into the argument positions on the stack. This is how the stack will | 1284 // that into the argument positions on the stack. This is how the stack will |
| 1458 // look (sp meaning the value of sp at this moment): | 1285 // look (sp meaning the value of sp at this moment): |
| 1459 // Abi n64: | 1286 // Abi n64: |
| 1460 // [sp + 1] - Argument 9 | 1287 // [sp + 1] - Argument 9 |
| 1461 // [sp + 0] - saved ra | 1288 // [sp + 0] - saved ra |
| 1462 // Abi O32: | 1289 // Abi O32: |
| 1463 // [sp + 5] - Argument 9 | 1290 // [sp + 5] - Argument 9 |
| 1464 // [sp + 4] - Argument 8 | 1291 // [sp + 4] - Argument 8 |
| 1465 // [sp + 3] - Argument 7 | 1292 // [sp + 3] - Argument 7 |
| 1466 // [sp + 2] - Argument 6 | 1293 // [sp + 2] - Argument 6 |
| 1467 // [sp + 1] - Argument 5 | 1294 // [sp + 1] - Argument 5 |
| 1468 // [sp + 0] - saved ra | 1295 // [sp + 0] - saved ra |
| 1469 | 1296 |
| 1470 // Argument 9: Pass current isolate address. | 1297 // Argument 9: Pass current isolate address. |
| 1471 __ li(a0, Operand(ExternalReference::isolate_address(isolate()))); | 1298 __ li(t1, Operand(ExternalReference::isolate_address(isolate()))); |
| 1472 __ sd(a0, MemOperand(sp, 1 * kPointerSize)); | 1299 __ sd(t1, MemOperand(sp, 1 * kPointerSize)); |
| 1473 | 1300 |
| 1474 // Argument 8: Indicate that this is a direct call from JavaScript. | 1301 // Argument 8: Indicate that this is a direct call from JavaScript. |
| 1475 __ li(a7, Operand(1)); | 1302 __ li(a7, Operand(1)); |
| 1476 | 1303 |
| 1477 // Argument 7: Start (high end) of backtracking stack memory area. | 1304 // Argument 7: Start (high end) of backtracking stack memory area. |
| 1478 __ li(a0, Operand(address_of_regexp_stack_memory_address)); | 1305 ExternalReference address_of_regexp_stack_memory_address = |
| 1479 __ ld(a0, MemOperand(a0, 0)); | 1306 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
| 1480 __ li(a2, Operand(address_of_regexp_stack_memory_size)); | 1307 ExternalReference address_of_regexp_stack_memory_size = |
| 1481 __ ld(a2, MemOperand(a2, 0)); | 1308 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
| 1482 __ daddu(a6, a0, a2); | 1309 __ li(t1, Operand(address_of_regexp_stack_memory_address)); |
| 1310 __ ld(t1, MemOperand(t1, 0)); |
| 1311 __ li(t2, Operand(address_of_regexp_stack_memory_size)); |
| 1312 __ ld(t2, MemOperand(t2, 0)); |
| 1313 __ daddu(a6, t1, t2); |
| 1483 | 1314 |
| 1484 // Argument 6: Set the number of capture registers to zero to force global | 1315 // Argument 6: Set the number of capture registers to zero to force global |
| 1485 // regexps to behave as non-global. This does not affect non-global regexps. | 1316 // regexps to behave as non-global. This does not affect non-global regexps. |
| 1486 __ mov(a5, zero_reg); | 1317 __ mov(a5, zero_reg); |
| 1487 | 1318 |
| 1488 // Argument 5: static offsets vector buffer. | 1319 // Argument 5: static offsets vector buffer. |
| 1489 __ li( | 1320 __ li( |
| 1490 a4, | 1321 a4, |
| 1491 Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); | 1322 Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); |
| 1492 | 1323 |
| 1493 // For arguments 4 and 3 get string length, calculate start of string data | |
| 1494 // and calculate the shift of the index (0 for one_byte and 1 for two byte). | |
| 1495 __ Daddu(t2, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); | |
| 1496 __ Xor(a3, a3, Operand(1)); // 1 for 2-byte str, 0 for 1-byte. | |
| 1497 // Load the length from the original subject string from the previous stack | |
| 1498 // frame. Therefore we have to use fp, which points exactly to two pointer | |
| 1499 // sizes below the previous sp. (Because creating a new stack frame pushes | |
| 1500 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) | |
| 1501 __ ld(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | |
| 1502 // If slice offset is not 0, load the length from the original sliced string. | |
| 1503 // Argument 4, a3: End of string data | 1324 // Argument 4, a3: End of string data |
| 1504 // Argument 3, a2: Start of string data | 1325 // Argument 3, a2: Start of string data |
| 1505 // Prepare start and end index of the input. | 1326 CHECK(a3.is(RegExpExecDescriptor::StringEndRegister())); |
| 1506 __ dsllv(t1, t0, a3); | 1327 CHECK(a2.is(RegExpExecDescriptor::StringStartRegister())); |
| 1507 __ daddu(t0, t2, t1); | |
| 1508 __ dsllv(t1, a1, a3); | |
| 1509 __ daddu(a2, t0, t1); | |
| 1510 | 1328 |
| 1511 __ ld(t2, FieldMemOperand(subject, String::kLengthOffset)); | |
| 1512 | |
| 1513 __ SmiUntag(t2); | |
| 1514 __ dsllv(t1, t2, a3); | |
| 1515 __ daddu(a3, t0, t1); | |
| 1516 // Argument 2 (a1): Previous index. | 1329 // Argument 2 (a1): Previous index. |
| 1517 // Already there | 1330 CHECK(a1.is(RegExpExecDescriptor::LastIndexRegister())); |
| 1518 | 1331 |
| 1519 // Argument 1 (a0): Subject string. | 1332 // Argument 1 (a0): Subject string. |
| 1520 __ mov(a0, subject); | 1333 CHECK(a0.is(RegExpExecDescriptor::StringRegister())); |
| 1521 | 1334 |
| 1522 // Locate the code entry and call it. | 1335 // Locate the code entry and call it. |
| 1523 __ Daddu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); | 1336 Register code_reg = RegExpExecDescriptor::CodeRegister(); |
| 1337 __ Daddu(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 1524 DirectCEntryStub stub(isolate()); | 1338 DirectCEntryStub stub(isolate()); |
| 1525 stub.GenerateCall(masm, t9); | 1339 stub.GenerateCall(masm, code_reg); |
| 1526 | 1340 |
| 1527 __ LeaveExitFrame(false, no_reg, true); | 1341 __ LeaveExitFrame(false, no_reg, true); |
| 1528 | 1342 |
| 1529 // v0: result | 1343 // Return the smi-tagged result. |
| 1530 // subject: subject string (callee saved) | 1344 __ SmiTag(v0); |
| 1531 // regexp_data: RegExp data (callee saved) | 1345 __ Ret(); |
| 1532 // last_match_info_elements: Last match info elements (callee saved) | |
| 1533 // Check the result. | |
| 1534 Label success; | |
| 1535 __ Branch(&success, eq, v0, Operand(1)); | |
| 1536 // We expect exactly one result since we force the called regexp to behave | |
| 1537 // as non-global. | |
| 1538 Label failure; | |
| 1539 __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE)); | |
| 1540 // If not exception it can only be retry. Handle that in the runtime system. | |
| 1541 __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | |
| 1542 // Result must now be exception. If there is no pending exception already a | |
| 1543 // stack overflow (on the backtrack stack) was detected in RegExp code but | |
| 1544 // haven't created the exception yet. Handle that in the runtime system. | |
| 1545 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | |
| 1546 __ li(a1, Operand(isolate()->factory()->the_hole_value())); | |
| 1547 __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | |
| 1548 isolate()))); | |
| 1549 __ ld(v0, MemOperand(a2, 0)); | |
| 1550 __ Branch(&runtime, eq, v0, Operand(a1)); | |
| 1551 | |
| 1552 // For exception, throw the exception again. | |
| 1553 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
| 1554 | |
| 1555 __ bind(&failure); | |
| 1556 // For failure and exception return null. | |
| 1557 __ li(v0, Operand(isolate()->factory()->null_value())); | |
| 1558 __ DropAndRet(4); | |
| 1559 | |
| 1560 // Process the result from the native regexp code. | |
| 1561 __ bind(&success); | |
| 1562 | |
| 1563 __ lw(a1, UntagSmiFieldMemOperand( | |
| 1564 regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | |
| 1565 // Calculate number of capture registers (number_of_captures + 1) * 2. | |
| 1566 __ Daddu(a1, a1, Operand(1)); | |
| 1567 __ dsll(a1, a1, 1); // Multiply by 2. | |
| 1568 | |
| 1569 // Check that the last match info is a FixedArray. | |
| 1570 __ ld(last_match_info_elements, MemOperand(sp, kLastMatchInfoOffset)); | |
| 1571 __ JumpIfSmi(last_match_info_elements, &runtime); | |
| 1572 // Check that the object has fast elements. | |
| 1573 __ ld(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | |
| 1574 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex); | |
| 1575 __ Branch(&runtime, ne, a0, Operand(at)); | |
| 1576 // Check that the last match info has space for the capture registers and the | |
| 1577 // additional information. | |
| 1578 __ ld(a0, | |
| 1579 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | |
| 1580 __ Daddu(a2, a1, Operand(RegExpMatchInfo::kLastMatchOverhead)); | |
| 1581 | |
| 1582 __ SmiUntag(at, a0); | |
| 1583 __ Branch(&runtime, gt, a2, Operand(at)); | |
| 1584 | |
| 1585 // a1: number of capture registers | |
| 1586 // subject: subject string | |
| 1587 // Store the capture count. | |
| 1588 __ SmiTag(a2, a1); // To smi. | |
| 1589 __ sd(a2, FieldMemOperand(last_match_info_elements, | |
| 1590 RegExpMatchInfo::kNumberOfCapturesOffset)); | |
| 1591 // Store last subject and last input. | |
| 1592 __ sd(subject, FieldMemOperand(last_match_info_elements, | |
| 1593 RegExpMatchInfo::kLastSubjectOffset)); | |
| 1594 __ mov(a2, subject); | |
| 1595 __ RecordWriteField(last_match_info_elements, | |
| 1596 RegExpMatchInfo::kLastSubjectOffset, subject, a7, | |
| 1597 kRAHasNotBeenSaved, kDontSaveFPRegs); | |
| 1598 __ mov(subject, a2); | |
| 1599 __ sd(subject, FieldMemOperand(last_match_info_elements, | |
| 1600 RegExpMatchInfo::kLastInputOffset)); | |
| 1601 __ RecordWriteField(last_match_info_elements, | |
| 1602 RegExpMatchInfo::kLastInputOffset, subject, a7, | |
| 1603 kRAHasNotBeenSaved, kDontSaveFPRegs); | |
| 1604 | |
| 1605 // Get the static offsets vector filled by the native regexp code. | |
| 1606 ExternalReference address_of_static_offsets_vector = | |
| 1607 ExternalReference::address_of_static_offsets_vector(isolate()); | |
| 1608 __ li(a2, Operand(address_of_static_offsets_vector)); | |
| 1609 | |
| 1610 // a1: number of capture registers | |
| 1611 // a2: offsets vector | |
| 1612 Label next_capture, done; | |
| 1613 // Capture register counter starts from number of capture registers and | |
| 1614 // counts down until wrapping after zero. | |
| 1615 __ Daddu(a0, last_match_info_elements, | |
| 1616 Operand(RegExpMatchInfo::kFirstCaptureOffset - kHeapObjectTag)); | |
| 1617 __ bind(&next_capture); | |
| 1618 __ Dsubu(a1, a1, Operand(1)); | |
| 1619 __ Branch(&done, lt, a1, Operand(zero_reg)); | |
| 1620 // Read the value from the static offsets vector buffer. | |
| 1621 __ lw(a3, MemOperand(a2, 0)); | |
| 1622 __ daddiu(a2, a2, kIntSize); | |
| 1623 // Store the smi value in the last match info. | |
| 1624 __ SmiTag(a3); | |
| 1625 __ sd(a3, MemOperand(a0, 0)); | |
| 1626 __ Branch(&next_capture, USE_DELAY_SLOT); | |
| 1627 __ daddiu(a0, a0, kPointerSize); // In branch delay slot. | |
| 1628 | |
| 1629 __ bind(&done); | |
| 1630 | |
| 1631 // Return last match info. | |
| 1632 __ mov(v0, last_match_info_elements); | |
| 1633 __ DropAndRet(4); | |
| 1634 | |
| 1635 // Do the runtime call to execute the regexp. | |
| 1636 __ bind(&runtime); | |
| 1637 __ TailCallRuntime(Runtime::kRegExpExec); | |
| 1638 | |
| 1639 // Deferred code for string handling. | |
| 1640 // (5) Long external string? If not, go to (7). | |
| 1641 __ bind(¬_seq_nor_cons); | |
| 1642 // Go to (7). | |
| 1643 __ Branch(¬_long_external, gt, a1, Operand(kExternalStringTag)); | |
| 1644 | |
| 1645 // (6) External string. Make it, offset-wise, look like a sequential string. | |
| 1646 __ bind(&external_string); | |
| 1647 __ ld(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
| 1648 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); | |
| 1649 if (FLAG_debug_code) { | |
| 1650 // Assert that we do not have a cons or slice (indirect strings) here. | |
| 1651 // Sequential strings have already been ruled out. | |
| 1652 __ And(at, a0, Operand(kIsIndirectStringMask)); | |
| 1653 __ Assert(eq, | |
| 1654 kExternalStringExpectedButNotFound, | |
| 1655 at, | |
| 1656 Operand(zero_reg)); | |
| 1657 } | |
| 1658 __ ld(subject, | |
| 1659 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | |
| 1660 // Move the pointer so that offset-wise, it looks like a sequential string. | |
| 1661 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
| 1662 __ Dsubu(subject, | |
| 1663 subject, | |
| 1664 SeqTwoByteString::kHeaderSize - kHeapObjectTag); | |
| 1665 __ jmp(&seq_string); // Go to (4). | |
| 1666 | |
| 1667 // (7) Short external string or not a string? If yes, bail out to runtime. | |
| 1668 __ bind(¬_long_external); | |
| 1669 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | |
| 1670 __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask)); | |
| 1671 __ Branch(&runtime, ne, at, Operand(zero_reg)); | |
| 1672 | |
| 1673 // (8) Sliced or thin string. Replace subject with parent. Go to (4). | |
| 1674 Label thin_string; | |
| 1675 __ Branch(&thin_string, eq, a1, Operand(kThinStringTag)); | |
| 1676 // Load offset into t0 and replace subject string with parent. | |
| 1677 __ ld(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); | |
| 1678 __ SmiUntag(t0); | |
| 1679 __ ld(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); | |
| 1680 __ jmp(&check_underlying); // Go to (1). | |
| 1681 | |
| 1682 __ bind(&thin_string); | |
| 1683 __ ld(subject, FieldMemOperand(subject, ThinString::kActualOffset)); | |
| 1684 __ jmp(&check_underlying); // Go to (1). | |
| 1685 #endif // V8_INTERPRETED_REGEXP | 1346 #endif // V8_INTERPRETED_REGEXP |
| 1686 } | 1347 } |
| 1687 | 1348 |
| 1688 | 1349 |
| 1689 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { | 1350 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { |
| 1690 // a0 : number of arguments to the construct function | 1351 // a0 : number of arguments to the construct function |
| 1691 // a2 : feedback vector | 1352 // a2 : feedback vector |
| 1692 // a3 : slot in feedback vector (Smi) | 1353 // a3 : slot in feedback vector (Smi) |
| 1693 // a1 : the function to call | 1354 // a1 : the function to call |
| 1694 FrameScope scope(masm, StackFrame::INTERNAL); | 1355 FrameScope scope(masm, StackFrame::INTERNAL); |
| (...skipping 1835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3530 kStackUnwindSpace, kInvalidStackOffset, | 3191 kStackUnwindSpace, kInvalidStackOffset, |
| 3531 return_value_operand, NULL); | 3192 return_value_operand, NULL); |
| 3532 } | 3193 } |
| 3533 | 3194 |
| 3534 #undef __ | 3195 #undef __ |
| 3535 | 3196 |
| 3536 } // namespace internal | 3197 } // namespace internal |
| 3537 } // namespace v8 | 3198 } // namespace v8 |
| 3538 | 3199 |
| 3539 #endif // V8_TARGET_ARCH_MIPS64 | 3200 #endif // V8_TARGET_ARCH_MIPS64 |
| OLD | NEW |