OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/api-arguments.h" | 7 #include "src/api-arguments.h" |
8 #include "src/arm64/assembler-arm64-inl.h" | 8 #include "src/arm64/assembler-arm64-inl.h" |
9 #include "src/arm64/frames-arm64.h" | 9 #include "src/arm64/frames-arm64.h" |
10 #include "src/arm64/macro-assembler-arm64-inl.h" | 10 #include "src/arm64/macro-assembler-arm64-inl.h" |
(...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1262 __ Mov(csp, jssp); | 1262 __ Mov(csp, jssp); |
1263 __ SetStackPointer(csp); | 1263 __ SetStackPointer(csp); |
1264 __ PopCalleeSavedRegisters(); | 1264 __ PopCalleeSavedRegisters(); |
1265 // After this point, we must not modify jssp because it is a callee-saved | 1265 // After this point, we must not modify jssp because it is a callee-saved |
1266 // register which we have just restored. | 1266 // register which we have just restored. |
1267 __ Ret(); | 1267 __ Ret(); |
1268 } | 1268 } |
1269 | 1269 |
1270 void RegExpExecStub::Generate(MacroAssembler* masm) { | 1270 void RegExpExecStub::Generate(MacroAssembler* masm) { |
1271 #ifdef V8_INTERPRETED_REGEXP | 1271 #ifdef V8_INTERPRETED_REGEXP |
1272 __ TailCallRuntime(Runtime::kRegExpExec); | 1272 // This case is handled prior to the RegExpExecStub call. |
| 1273 __ Abort(kUnexpectedRegExpExecCall); |
1273 #else // V8_INTERPRETED_REGEXP | 1274 #else // V8_INTERPRETED_REGEXP |
1274 | |
1275 // Stack frame on entry. | |
1276 // jssp[0]: last_match_info (expected JSArray) | |
1277 // jssp[8]: previous index | |
1278 // jssp[16]: subject string | |
1279 // jssp[24]: JSRegExp object | |
1280 Label runtime; | |
1281 | |
1282 // Use of registers for this function. | |
1283 | |
1284 // Variable registers: | |
1285 // x10-x13 used as scratch registers | |
1286 // w0 string_type type of subject string | |
1287 // x2 jsstring_length subject string length | |
1288 // x3 jsregexp_object JSRegExp object | |
1289 // w4 string_encoding Latin1 or UC16 | |
1290 // w5 sliced_string_offset if the string is a SlicedString | |
1291 // offset to the underlying string | |
1292 // w6 string_representation groups attributes of the string: | |
1293 // - is a string | |
1294 // - type of the string | |
1295 // - is a short external string | |
1296 Register string_type = w0; | |
1297 Register jsstring_length = x2; | |
1298 Register jsregexp_object = x3; | |
1299 Register string_encoding = w4; | |
1300 Register sliced_string_offset = w5; | |
1301 Register string_representation = w6; | |
1302 | |
1303 // These are in callee save registers and will be preserved by the call | |
1304 // to the native RegExp code, as this code is called using the normal | |
1305 // C calling convention. When calling directly from generated code the | |
1306 // native RegExp code will not do a GC and therefore the content of | |
1307 // these registers are safe to use after the call. | |
1308 | |
1309 // x19 subject subject string | |
1310 // x20 regexp_data RegExp data (FixedArray) | |
1311 // x21 last_match_info_elements info relative to the last match | |
1312 // (FixedArray) | |
1313 // x22 code_object generated regexp code | |
1314 Register subject = x19; | |
1315 Register regexp_data = x20; | |
1316 Register last_match_info_elements = x21; | |
1317 Register code_object = x22; | |
1318 | |
1319 // Stack frame. | |
1320 // jssp[00]: last_match_info (JSArray) | |
1321 // jssp[08]: previous index | |
1322 // jssp[16]: subject string | |
1323 // jssp[24]: JSRegExp object | |
1324 | |
1325 const int kLastMatchInfoOffset = 0 * kPointerSize; | |
1326 const int kPreviousIndexOffset = 1 * kPointerSize; | |
1327 const int kSubjectOffset = 2 * kPointerSize; | |
1328 const int kJSRegExpOffset = 3 * kPointerSize; | |
1329 | |
1330 // Ensure that a RegExp stack is allocated. | |
1331 ExternalReference address_of_regexp_stack_memory_address = | |
1332 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | |
1333 ExternalReference address_of_regexp_stack_memory_size = | |
1334 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
1335 __ Mov(x10, address_of_regexp_stack_memory_size); | |
1336 __ Ldr(x10, MemOperand(x10)); | |
1337 __ Cbz(x10, &runtime); | |
1338 | |
1339 // Check that the first argument is a JSRegExp object. | |
1340 DCHECK(jssp.Is(__ StackPointer())); | |
1341 __ Peek(jsregexp_object, kJSRegExpOffset); | |
1342 __ JumpIfSmi(jsregexp_object, &runtime); | |
1343 __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime); | |
1344 | |
1345 // Check that the RegExp has been compiled (data contains a fixed array). | |
1346 __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset)); | |
1347 if (FLAG_debug_code) { | |
1348 STATIC_ASSERT(kSmiTag == 0); | |
1349 __ Tst(regexp_data, kSmiTagMask); | |
1350 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
1351 __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE); | |
1352 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
1353 } | |
1354 | |
1355 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
1356 __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | |
1357 __ Cmp(x10, Smi::FromInt(JSRegExp::IRREGEXP)); | |
1358 __ B(ne, &runtime); | |
1359 | |
1360 // Check that the number of captures fit in the static offsets vector buffer. | |
1361 // We have always at least one capture for the whole match, plus additional | |
1362 // ones due to capturing parentheses. A capture takes 2 registers. | |
1363 // The number of capture registers then is (number_of_captures + 1) * 2. | |
1364 __ Ldrsw(x10, | |
1365 UntagSmiFieldMemOperand(regexp_data, | |
1366 JSRegExp::kIrregexpCaptureCountOffset)); | |
1367 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
1368 // number_of_captures * 2 <= offsets vector size - 2 | |
1369 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
1370 __ Add(x10, x10, x10); | |
1371 __ Cmp(x10, Isolate::kJSRegexpStaticOffsetsVectorSize - 2); | |
1372 __ B(hi, &runtime); | |
1373 | |
1374 // Initialize offset for possibly sliced string. | |
1375 __ Mov(sliced_string_offset, 0); | |
1376 | |
1377 DCHECK(jssp.Is(__ StackPointer())); | |
1378 __ Peek(subject, kSubjectOffset); | |
1379 __ JumpIfSmi(subject, &runtime); | |
1380 | |
1381 __ Ldr(jsstring_length, FieldMemOperand(subject, String::kLengthOffset)); | |
1382 | |
1383 // Handle subject string according to its encoding and representation: | |
1384 // (1) Sequential string? If yes, go to (4). | |
1385 // (2) Sequential or cons? If not, go to (5). | |
1386 // (3) Cons string. If the string is flat, replace subject with first string | |
1387 // and go to (1). Otherwise bail out to runtime. | |
1388 // (4) Sequential string. Load regexp code according to encoding. | |
1389 // (E) Carry on. | |
1390 /// [...] | |
1391 | |
1392 // Deferred code at the end of the stub: | |
1393 // (5) Long external string? If not, go to (7). | |
1394 // (6) External string. Make it, offset-wise, look like a sequential string. | |
1395 // Go to (4). | |
1396 // (7) Short external string or not a string? If yes, bail out to runtime. | |
1397 // (8) Sliced or thin string. Replace subject with parent. Go to (1). | |
1398 | |
1399 Label check_underlying; // (1) | |
1400 Label seq_string; // (4) | |
1401 Label not_seq_nor_cons; // (5) | |
1402 Label external_string; // (6) | |
1403 Label not_long_external; // (7) | |
1404 | |
1405 __ Bind(&check_underlying); | |
1406 __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
1407 __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset)); | |
1408 | |
1409 // (1) Sequential string? If yes, go to (4). | |
1410 __ And(string_representation, | |
1411 string_type, | |
1412 kIsNotStringMask | | |
1413 kStringRepresentationMask | | |
1414 kShortExternalStringMask); | |
1415 // We depend on the fact that Strings of type | |
1416 // SeqString and not ShortExternalString are defined | |
1417 // by the following pattern: | |
1418 // string_type: 0XX0 XX00 | |
1419 // ^ ^ ^^ | |
1420 // | | || | |
1421 // | | is a SeqString | |
1422 // | is not a short external String | |
1423 // is a String | |
1424 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | |
1425 STATIC_ASSERT(kShortExternalStringTag != 0); | |
1426 __ Cbz(string_representation, &seq_string); // Go to (4). | |
1427 | |
1428 // (2) Sequential or cons? If not, go to (5). | |
1429 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
1430 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
1431 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
1432 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
1433 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
1434 __ Cmp(string_representation, kExternalStringTag); | |
1435 __ B(ge, ¬_seq_nor_cons); // Go to (5). | |
1436 | |
1437 // (3) Cons string. Check that it's flat. | |
1438 __ Ldr(x10, FieldMemOperand(subject, ConsString::kSecondOffset)); | |
1439 __ JumpIfNotRoot(x10, Heap::kempty_stringRootIndex, &runtime); | |
1440 // Replace subject with first string. | |
1441 __ Ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | |
1442 __ B(&check_underlying); | |
1443 | |
1444 // (4) Sequential string. Load regexp code according to encoding. | |
1445 __ Bind(&seq_string); | |
1446 | |
1447 // Check that the third argument is a positive smi less than the subject | |
1448 // string length. A negative value will be greater (unsigned comparison). | |
1449 DCHECK(jssp.Is(__ StackPointer())); | |
1450 __ Peek(x10, kPreviousIndexOffset); | |
1451 __ JumpIfNotSmi(x10, &runtime); | |
1452 __ Cmp(jsstring_length, x10); | |
1453 __ B(ls, &runtime); | |
1454 | |
1455 // Argument 2 (x1): We need to load argument 2 (the previous index) into x1 | |
1456 // before entering the exit frame. | |
1457 __ SmiUntag(x1, x10); | |
1458 | |
1459 // The fourth bit determines the string encoding in string_type. | |
1460 STATIC_ASSERT(kOneByteStringTag == 0x08); | |
1461 STATIC_ASSERT(kTwoByteStringTag == 0x00); | |
1462 STATIC_ASSERT(kStringEncodingMask == 0x08); | |
1463 | |
1464 // Find the code object based on the assumptions above. | |
1465 // kDataOneByteCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset | |
1466 // of kPointerSize to reach the latter. | |
1467 STATIC_ASSERT(JSRegExp::kDataOneByteCodeOffset + kPointerSize == | |
1468 JSRegExp::kDataUC16CodeOffset); | |
1469 __ Mov(x10, kPointerSize); | |
1470 // We will need the encoding later: Latin1 = 0x08 | |
1471 // UC16 = 0x00 | |
1472 __ Ands(string_encoding, string_type, kStringEncodingMask); | |
1473 __ CzeroX(x10, ne); | |
1474 __ Add(x10, regexp_data, x10); | |
1475 __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataOneByteCodeOffset)); | |
1476 | |
1477 // (E) Carry on. String handling is done. | |
1478 | |
1479 // Check that the irregexp code has been generated for the actual string | |
1480 // encoding. If it has, the field contains a code object otherwise it contains | |
1481 // a smi (code flushing support). | |
1482 __ JumpIfSmi(code_object, &runtime); | |
1483 | |
1484 // All checks done. Now push arguments for native regexp code. | |
1485 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, | |
1486 x10, | |
1487 x11); | |
1488 | |
1489 // Isolates: note we add an additional parameter here (isolate pointer). | 1275 // Isolates: note we add an additional parameter here (isolate pointer). |
1490 __ EnterExitFrame(false, x10, 1); | 1276 __ EnterExitFrame(false, x10, 1); |
1491 DCHECK(csp.Is(__ StackPointer())); | 1277 DCHECK(csp.Is(__ StackPointer())); |
1492 | 1278 |
1493 // We have 9 arguments to pass to the regexp code, therefore we have to pass | 1279 // We have 9 arguments to pass to the regexp code, therefore we have to pass |
1494 // one on the stack and the rest as registers. | 1280 // one on the stack and the rest as registers. |
1495 | 1281 |
1496 // Note that the placement of the argument on the stack isn't standard | 1282 // Note that the placement of the argument on the stack isn't standard |
1497 // AAPCS64: | 1283 // AAPCS64: |
1498 // csp[0]: Space for the return address placed by DirectCEntryStub. | 1284 // csp[0]: Space for the return address placed by DirectCEntryStub. |
1499 // csp[8]: Argument 9, the current isolate address. | 1285 // csp[8]: Argument 9, the current isolate address. |
1500 | 1286 |
1501 __ Mov(x10, ExternalReference::isolate_address(isolate())); | 1287 __ Mov(x10, ExternalReference::isolate_address(isolate())); |
1502 __ Poke(x10, kPointerSize); | 1288 __ Poke(x10, kPointerSize); |
1503 | 1289 |
1504 Register length = w11; | |
1505 Register previous_index_in_bytes = w12; | |
1506 Register start = x13; | |
1507 | |
1508 // Load start of the subject string. | |
1509 __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag); | |
1510 // Load the length from the original subject string from the previous stack | |
1511 // frame. Therefore we have to use fp, which points exactly to two pointer | |
1512 // sizes below the previous sp. (Because creating a new stack frame pushes | |
1513 // the previous fp onto the stack and decrements sp by 2 * kPointerSize.) | |
1514 __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | |
1515 __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset)); | |
1516 | |
1517 // Handle UC16 encoding, two bytes make one character. | |
1518 // string_encoding: if Latin1: 0x08 | |
1519 // if UC16: 0x00 | |
1520 STATIC_ASSERT(kStringEncodingMask == 0x08); | |
1521 __ Ubfx(string_encoding, string_encoding, 3, 1); | |
1522 __ Eor(string_encoding, string_encoding, 1); | |
1523 // string_encoding: if Latin1: 0 | |
1524 // if UC16: 1 | |
1525 | |
1526 // Convert string positions from characters to bytes. | |
1527 // Previous index is in x1. | |
1528 __ Lsl(previous_index_in_bytes, w1, string_encoding); | |
1529 __ Lsl(length, length, string_encoding); | |
1530 __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding); | |
1531 | |
1532 // Argument 1 (x0): Subject string. | 1290 // Argument 1 (x0): Subject string. |
1533 __ Mov(x0, subject); | 1291 CHECK(x0.is(RegExpExecDescriptor::StringRegister())); |
1534 | 1292 |
1535 // Argument 2 (x1): Previous index, already there. | 1293 // Argument 2 (x1): Previous index, already there. |
| 1294 CHECK(x1.is(RegExpExecDescriptor::LastIndexRegister())); |
1536 | 1295 |
1537 // Argument 3 (x2): Get the start of input. | 1296 // Argument 3 (x2): Input start. |
1538 // Start of input = start of string + previous index + substring offset | 1297 // Argument 4 (x3): Input end. |
1539 // (0 if the string | 1298 CHECK(x2.is(RegExpExecDescriptor::StringStartRegister())); |
1540 // is not sliced). | 1299 CHECK(x3.is(RegExpExecDescriptor::StringEndRegister())); |
1541 __ Add(w10, previous_index_in_bytes, sliced_string_offset); | |
1542 __ Add(x2, start, Operand(w10, UXTW)); | |
1543 | |
1544 // Argument 4 (x3): | |
1545 // End of input = start of input + (length of input - previous index) | |
1546 __ Sub(w10, length, previous_index_in_bytes); | |
1547 __ Add(x3, x2, Operand(w10, UXTW)); | |
1548 | 1300 |
1549 // Argument 5 (x4): static offsets vector buffer. | 1301 // Argument 5 (x4): static offsets vector buffer. |
1550 __ Mov(x4, ExternalReference::address_of_static_offsets_vector(isolate())); | 1302 __ Mov(x4, ExternalReference::address_of_static_offsets_vector(isolate())); |
1551 | 1303 |
1552 // Argument 6 (x5): Set the number of capture registers to zero to force | 1304 // Argument 6 (x5): Set the number of capture registers to zero to force |
1553 // global regexps to behave as non-global. This stub is not used for global | 1305 // global regexps to behave as non-global. This stub is not used for global |
1554 // regexps. | 1306 // regexps. |
1555 __ Mov(x5, 0); | 1307 __ Mov(x5, 0); |
1556 | 1308 |
1557 // Argument 7 (x6): Start (high end) of backtracking stack memory area. | 1309 // Argument 7 (x6): Start (high end) of backtracking stack memory area. |
| 1310 ExternalReference address_of_regexp_stack_memory_address = |
| 1311 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
| 1312 ExternalReference address_of_regexp_stack_memory_size = |
| 1313 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
1558 __ Mov(x10, address_of_regexp_stack_memory_address); | 1314 __ Mov(x10, address_of_regexp_stack_memory_address); |
1559 __ Ldr(x10, MemOperand(x10)); | 1315 __ Ldr(x10, MemOperand(x10)); |
1560 __ Mov(x11, address_of_regexp_stack_memory_size); | 1316 __ Mov(x11, address_of_regexp_stack_memory_size); |
1561 __ Ldr(x11, MemOperand(x11)); | 1317 __ Ldr(x11, MemOperand(x11)); |
1562 __ Add(x6, x10, x11); | 1318 __ Add(x6, x10, x11); |
1563 | 1319 |
1564 // Argument 8 (x7): Indicate that this is a direct call from JavaScript. | 1320 // Argument 8 (x7): Indicate that this is a direct call from JavaScript. |
1565 __ Mov(x7, 1); | 1321 __ Mov(x7, 1); |
1566 | 1322 |
1567 // Locate the code entry and call it. | 1323 // Locate the code entry and call it. |
| 1324 Register code_object = RegExpExecDescriptor::CodeRegister(); |
1568 __ Add(code_object, code_object, Code::kHeaderSize - kHeapObjectTag); | 1325 __ Add(code_object, code_object, Code::kHeaderSize - kHeapObjectTag); |
1569 DirectCEntryStub stub(isolate()); | 1326 DirectCEntryStub stub(isolate()); |
1570 stub.GenerateCall(masm, code_object); | 1327 stub.GenerateCall(masm, code_object); |
1571 | 1328 |
1572 __ LeaveExitFrame(false, x10, true); | 1329 __ LeaveExitFrame(false, x10, true); |
1573 | 1330 |
1574 // The generated regexp code returns an int32 in w0. | 1331 // Return the smi-tagged result. |
1575 Label failure, exception; | 1332 __ SmiTag(x0); |
1576 __ CompareAndBranch(w0, NativeRegExpMacroAssembler::FAILURE, eq, &failure); | |
1577 __ CompareAndBranch(w0, | |
1578 NativeRegExpMacroAssembler::EXCEPTION, | |
1579 eq, | |
1580 &exception); | |
1581 __ CompareAndBranch(w0, NativeRegExpMacroAssembler::RETRY, eq, &runtime); | |
1582 | |
1583 // Success: process the result from the native regexp code. | |
1584 Register number_of_capture_registers = x12; | |
1585 | |
1586 // Calculate number of capture registers (number_of_captures + 1) * 2 | |
1587 // and store it in the last match info. | |
1588 __ Ldrsw(x10, | |
1589 UntagSmiFieldMemOperand(regexp_data, | |
1590 JSRegExp::kIrregexpCaptureCountOffset)); | |
1591 __ Add(x10, x10, x10); | |
1592 __ Add(number_of_capture_registers, x10, 2); | |
1593 | |
1594 // Check that the last match info is a FixedArray. | |
1595 DCHECK(jssp.Is(__ StackPointer())); | |
1596 __ Peek(last_match_info_elements, kLastMatchInfoOffset); | |
1597 __ JumpIfSmi(last_match_info_elements, &runtime); | |
1598 | |
1599 // Check that the object has fast elements. | |
1600 __ Ldr(x10, | |
1601 FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | |
1602 __ JumpIfNotRoot(x10, Heap::kFixedArrayMapRootIndex, &runtime); | |
1603 | |
1604 // Check that the last match info has space for the capture registers and the | |
1605 // additional information (overhead). | |
1606 // (number_of_captures + 1) * 2 + overhead <= last match info size | |
1607 // (number_of_captures * 2) + 2 + overhead <= last match info size | |
1608 // number_of_capture_registers + overhead <= last match info size | |
1609 __ Ldrsw(x10, | |
1610 UntagSmiFieldMemOperand(last_match_info_elements, | |
1611 FixedArray::kLengthOffset)); | |
1612 __ Add(x11, number_of_capture_registers, RegExpMatchInfo::kLastMatchOverhead); | |
1613 __ Cmp(x11, x10); | |
1614 __ B(gt, &runtime); | |
1615 | |
1616 // Store the capture count. | |
1617 __ SmiTag(x10, number_of_capture_registers); | |
1618 __ Str(x10, FieldMemOperand(last_match_info_elements, | |
1619 RegExpMatchInfo::kNumberOfCapturesOffset)); | |
1620 // Store last subject and last input. | |
1621 __ Str(subject, FieldMemOperand(last_match_info_elements, | |
1622 RegExpMatchInfo::kLastSubjectOffset)); | |
1623 // Use x10 as the subject string in order to only need | |
1624 // one RecordWriteStub. | |
1625 __ Mov(x10, subject); | |
1626 __ RecordWriteField(last_match_info_elements, | |
1627 RegExpMatchInfo::kLastSubjectOffset, x10, x11, | |
1628 kLRHasNotBeenSaved, kDontSaveFPRegs); | |
1629 __ Str(subject, FieldMemOperand(last_match_info_elements, | |
1630 RegExpMatchInfo::kLastInputOffset)); | |
1631 __ Mov(x10, subject); | |
1632 __ RecordWriteField(last_match_info_elements, | |
1633 RegExpMatchInfo::kLastInputOffset, x10, x11, | |
1634 kLRHasNotBeenSaved, kDontSaveFPRegs); | |
1635 | |
1636 Register last_match_offsets = x13; | |
1637 Register offsets_vector_index = x14; | |
1638 Register current_offset = x15; | |
1639 | |
1640 // Get the static offsets vector filled by the native regexp code | |
1641 // and fill the last match info. | |
1642 ExternalReference address_of_static_offsets_vector = | |
1643 ExternalReference::address_of_static_offsets_vector(isolate()); | |
1644 __ Mov(offsets_vector_index, address_of_static_offsets_vector); | |
1645 | |
1646 Label next_capture, done; | |
1647 // Capture register counter starts from number of capture registers and | |
1648 // iterates down to zero (inclusive). | |
1649 __ Add(last_match_offsets, last_match_info_elements, | |
1650 RegExpMatchInfo::kFirstCaptureOffset - kHeapObjectTag); | |
1651 __ Bind(&next_capture); | |
1652 __ Subs(number_of_capture_registers, number_of_capture_registers, 2); | |
1653 __ B(mi, &done); | |
1654 // Read two 32 bit values from the static offsets vector buffer into | |
1655 // an X register | |
1656 __ Ldr(current_offset, | |
1657 MemOperand(offsets_vector_index, kWRegSize * 2, PostIndex)); | |
1658 // Store the smi values in the last match info. | |
1659 __ SmiTag(x10, current_offset); | |
1660 // Clearing the 32 bottom bits gives us a Smi. | |
1661 STATIC_ASSERT(kSmiTag == 0); | |
1662 __ Bic(x11, current_offset, kSmiShiftMask); | |
1663 __ Stp(x10, | |
1664 x11, | |
1665 MemOperand(last_match_offsets, kXRegSize * 2, PostIndex)); | |
1666 __ B(&next_capture); | |
1667 __ Bind(&done); | |
1668 | |
1669 // Return last match info. | |
1670 __ Mov(x0, last_match_info_elements); | |
1671 // Drop the 4 arguments of the stub from the stack. | |
1672 __ Drop(4); | |
1673 __ Ret(); | 1333 __ Ret(); |
1674 | |
1675 __ Bind(&exception); | |
1676 Register exception_value = x0; | |
1677 // A stack overflow (on the backtrack stack) may have occured | |
1678 // in the RegExp code but no exception has been created yet. | |
1679 // If there is no pending exception, handle that in the runtime system. | |
1680 __ Mov(x10, Operand(isolate()->factory()->the_hole_value())); | |
1681 __ Mov(x11, | |
1682 Operand(ExternalReference(Isolate::kPendingExceptionAddress, | |
1683 isolate()))); | |
1684 __ Ldr(exception_value, MemOperand(x11)); | |
1685 __ Cmp(x10, exception_value); | |
1686 __ B(eq, &runtime); | |
1687 | |
1688 // For exception, throw the exception again. | |
1689 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
1690 | |
1691 __ Bind(&failure); | |
1692 __ Mov(x0, Operand(isolate()->factory()->null_value())); | |
1693 // Drop the 4 arguments of the stub from the stack. | |
1694 __ Drop(4); | |
1695 __ Ret(); | |
1696 | |
1697 __ Bind(&runtime); | |
1698 __ TailCallRuntime(Runtime::kRegExpExec); | |
1699 | |
1700 // Deferred code for string handling. | |
1701 // (5) Long external string? If not, go to (7). | |
1702 __ Bind(¬_seq_nor_cons); | |
1703 // Compare flags are still set. | |
1704 __ B(ne, ¬_long_external); // Go to (7). | |
1705 | |
1706 // (6) External string. Make it, offset-wise, look like a sequential string. | |
1707 __ Bind(&external_string); | |
1708 if (masm->emit_debug_code()) { | |
1709 // Assert that we do not have a cons or slice (indirect strings) here. | |
1710 // Sequential strings have already been ruled out. | |
1711 __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
1712 __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset)); | |
1713 __ Tst(x10, kIsIndirectStringMask); | |
1714 __ Check(eq, kExternalStringExpectedButNotFound); | |
1715 __ And(x10, x10, kStringRepresentationMask); | |
1716 __ Cmp(x10, 0); | |
1717 __ Check(ne, kExternalStringExpectedButNotFound); | |
1718 } | |
1719 __ Ldr(subject, | |
1720 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | |
1721 // Move the pointer so that offset-wise, it looks like a sequential string. | |
1722 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
1723 __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag); | |
1724 __ B(&seq_string); // Go to (4). | |
1725 | |
1726 // (7) If this is a short external string or not a string, bail out to | |
1727 // runtime. | |
1728 __ Bind(¬_long_external); | |
1729 STATIC_ASSERT(kShortExternalStringTag != 0); | |
1730 __ TestAndBranchIfAnySet(string_representation, | |
1731 kShortExternalStringMask | kIsNotStringMask, | |
1732 &runtime); | |
1733 | |
1734 // (8) Sliced or thin string. Replace subject with parent. | |
1735 Label thin_string; | |
1736 __ Cmp(string_representation, kThinStringTag); | |
1737 __ B(eq, &thin_string); | |
1738 __ Ldr(sliced_string_offset, | |
1739 UntagSmiFieldMemOperand(subject, SlicedString::kOffsetOffset)); | |
1740 __ Ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); | |
1741 __ B(&check_underlying); // Go to (1). | |
1742 | |
1743 __ bind(&thin_string); | |
1744 __ Ldr(subject, FieldMemOperand(subject, ThinString::kActualOffset)); | |
1745 __ B(&check_underlying); // Go to (1). | |
1746 #endif | 1334 #endif |
1747 } | 1335 } |
1748 | 1336 |
1749 | 1337 |
1750 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, | 1338 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, |
1751 Register argc, Register function, | 1339 Register argc, Register function, |
1752 Register feedback_vector, Register index, | 1340 Register feedback_vector, Register index, |
1753 Register new_target) { | 1341 Register new_target) { |
1754 FrameScope scope(masm, StackFrame::INTERNAL); | 1342 FrameScope scope(masm, StackFrame::INTERNAL); |
1755 | 1343 |
(...skipping 1886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3642 kStackUnwindSpace, NULL, spill_offset, | 3230 kStackUnwindSpace, NULL, spill_offset, |
3643 return_value_operand, NULL); | 3231 return_value_operand, NULL); |
3644 } | 3232 } |
3645 | 3233 |
3646 #undef __ | 3234 #undef __ |
3647 | 3235 |
3648 } // namespace internal | 3236 } // namespace internal |
3649 } // namespace v8 | 3237 } // namespace v8 |
3650 | 3238 |
3651 #endif // V8_TARGET_ARCH_ARM64 | 3239 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |