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