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_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/api-arguments.h" | 7 #include "src/api-arguments.h" |
8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 2); | 344 2); |
345 } | 345 } |
346 // Return value is in xmm0. | 346 // Return value is in xmm0. |
347 __ Movsd(double_result, xmm0); | 347 __ Movsd(double_result, xmm0); |
348 | 348 |
349 __ bind(&done); | 349 __ bind(&done); |
350 __ ret(0); | 350 __ ret(0); |
351 } | 351 } |
352 | 352 |
353 void RegExpExecStub::Generate(MacroAssembler* masm) { | 353 void RegExpExecStub::Generate(MacroAssembler* masm) { |
354 // Just jump directly to runtime if native RegExp is not selected at compile | |
355 // time or if regexp entry in generated code is turned off runtime switch or | |
356 // at compilation. | |
357 #ifdef V8_INTERPRETED_REGEXP | 354 #ifdef V8_INTERPRETED_REGEXP |
358 __ TailCallRuntime(Runtime::kRegExpExec); | 355 // This case is handled prior to the RegExpExecStub call. |
| 356 __ Abort(kUnexpectedRegExpExecCall); |
359 #else // V8_INTERPRETED_REGEXP | 357 #else // V8_INTERPRETED_REGEXP |
360 | |
361 // Stack frame on entry. | |
362 // rsp[0] : return address | |
363 // rsp[8] : last_match_info (expected JSArray) | |
364 // rsp[16] : previous index | |
365 // rsp[24] : subject string | |
366 // rsp[32] : JSRegExp object | |
367 | |
368 enum RegExpExecStubArgumentIndices { | |
369 JS_REG_EXP_OBJECT_ARGUMENT_INDEX, | |
370 SUBJECT_STRING_ARGUMENT_INDEX, | |
371 PREVIOUS_INDEX_ARGUMENT_INDEX, | |
372 LAST_MATCH_INFO_ARGUMENT_INDEX, | |
373 REG_EXP_EXEC_ARGUMENT_COUNT | |
374 }; | |
375 | |
376 StackArgumentsAccessor args(rsp, REG_EXP_EXEC_ARGUMENT_COUNT, | |
377 ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
378 Label runtime; | |
379 // Ensure that a RegExp stack is allocated. | |
380 ExternalReference address_of_regexp_stack_memory_address = | |
381 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | |
382 ExternalReference address_of_regexp_stack_memory_size = | |
383 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
384 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); | |
385 __ testp(kScratchRegister, kScratchRegister); | |
386 __ j(zero, &runtime); | |
387 | |
388 // Check that the first argument is a JSRegExp object. | |
389 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); | |
390 __ JumpIfSmi(rax, &runtime); | |
391 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); | |
392 __ j(not_equal, &runtime); | |
393 | |
394 // Check that the RegExp has been compiled (data contains a fixed array). | |
395 __ movp(rax, FieldOperand(rax, JSRegExp::kDataOffset)); | |
396 if (FLAG_debug_code) { | |
397 Condition is_smi = masm->CheckSmi(rax); | |
398 __ Check(NegateCondition(is_smi), | |
399 kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
400 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); | |
401 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
402 } | |
403 | |
404 // rax: RegExp data (FixedArray) | |
405 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
406 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); | |
407 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); | |
408 __ j(not_equal, &runtime); | |
409 | |
410 // rax: RegExp data (FixedArray) | |
411 // Check that the number of captures fit in the static offsets vector buffer. | |
412 __ SmiToInteger32(rdx, | |
413 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); | |
414 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
415 // Or number_of_captures <= offsets vector size / 2 - 1 | |
416 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
417 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); | |
418 __ j(above, &runtime); | |
419 | |
420 // Reset offset for possibly sliced string. | |
421 __ Set(r14, 0); | |
422 __ movp(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); | |
423 __ JumpIfSmi(rdi, &runtime); | |
424 __ movp(r15, rdi); // Make a copy of the original subject string. | |
425 // rax: RegExp data (FixedArray) | |
426 // rdi: subject string | |
427 // r15: subject string | |
428 // Handle subject string according to its encoding and representation: | |
429 // (1) Sequential two byte? If yes, go to (9). | |
430 // (2) Sequential one byte? If yes, go to (5). | |
431 // (3) Sequential or cons? If not, go to (6). | |
432 // (4) Cons string. If the string is flat, replace subject with first string | |
433 // and go to (1). Otherwise bail out to runtime. | |
434 // (5) One byte sequential. Load regexp code for one byte. | |
435 // (E) Carry on. | |
436 /// [...] | |
437 | |
438 // Deferred code at the end of the stub: | |
439 // (6) Long external string? If not, go to (10). | |
440 // (7) External string. Make it, offset-wise, look like a sequential string. | |
441 // (8) Is the external string one byte? If yes, go to (5). | |
442 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
443 // (10) Short external string or not a string? If yes, bail out to runtime. | |
444 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
445 | |
446 Label seq_one_byte_string /* 5 */, seq_two_byte_string /* 9 */, | |
447 external_string /* 7 */, check_underlying /* 1 */, | |
448 not_seq_nor_cons /* 6 */, check_code /* E */, not_long_external /* 10 */; | |
449 | |
450 __ bind(&check_underlying); | |
451 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | |
452 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
453 | |
454 // (1) Sequential two byte? If yes, go to (9). | |
455 __ andb(rbx, Immediate(kIsNotStringMask | | |
456 kStringRepresentationMask | | |
457 kStringEncodingMask | | |
458 kShortExternalStringMask)); | |
459 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | |
460 __ j(zero, &seq_two_byte_string); // Go to (9). | |
461 | |
462 // (2) Sequential one byte? If yes, go to (5). | |
463 // Any other sequential string must be one byte. | |
464 __ andb(rbx, Immediate(kIsNotStringMask | | |
465 kStringRepresentationMask | | |
466 kShortExternalStringMask)); | |
467 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (5). | |
468 | |
469 // (3) Sequential or cons? If not, go to (6). | |
470 // We check whether the subject string is a cons, since sequential strings | |
471 // have already been covered. | |
472 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
473 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
474 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
475 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
476 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
477 __ cmpp(rbx, Immediate(kExternalStringTag)); | |
478 __ j(greater_equal, ¬_seq_nor_cons); // Go to (6). | |
479 | |
480 // (4) Cons string. Check that it's flat. | |
481 // Replace subject with first string and reload instance type. | |
482 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | |
483 Heap::kempty_stringRootIndex); | |
484 __ j(not_equal, &runtime); | |
485 __ movp(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | |
486 __ jmp(&check_underlying); | |
487 | |
488 // (5) One byte sequential. Load regexp code for one byte. | |
489 __ bind(&seq_one_byte_string); | |
490 // rax: RegExp data (FixedArray) | |
491 __ movp(r11, FieldOperand(rax, JSRegExp::kDataOneByteCodeOffset)); | |
492 __ Set(rcx, 1); // Type is one byte. | |
493 | |
494 // (E) Carry on. String handling is done. | |
495 __ bind(&check_code); | |
496 // r11: irregexp code | |
497 // Check that the irregexp code has been generated for the actual string | |
498 // encoding. If it has, the field contains a code object otherwise it contains | |
499 // smi (code flushing support) | |
500 __ JumpIfSmi(r11, &runtime); | |
501 | |
502 // rdi: sequential subject string (or look-alike, external string) | |
503 // r15: original subject string | |
504 // rcx: encoding of subject string (1 if one_byte, 0 if two_byte); | |
505 // r11: code | |
506 // Load used arguments before starting to push arguments for call to native | |
507 // RegExp code to avoid handling changing stack height. | |
508 // We have to use r15 instead of rdi to load the length because rdi might | |
509 // have been only made to look like a sequential string when it actually | |
510 // is an external string. | |
511 __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); | |
512 __ JumpIfNotSmi(rbx, &runtime); | |
513 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); | |
514 __ j(above_equal, &runtime); | |
515 __ SmiToInteger64(rbx, rbx); | |
516 | |
517 // rdi: subject string | |
518 // rbx: previous index | |
519 // rcx: encoding of subject string (1 if one_byte 0 if two_byte); | |
520 // r11: code | |
521 // All checks done. Now push arguments for native regexp code. | |
522 Counters* counters = isolate()->counters(); | |
523 __ IncrementCounter(counters->regexp_entry_native(), 1); | |
524 | |
525 // Isolates: note we add an additional parameter here (isolate pointer). | 358 // Isolates: note we add an additional parameter here (isolate pointer). |
526 static const int kRegExpExecuteArguments = 9; | 359 static const int kRegExpExecuteArguments = 9; |
527 int argument_slots_on_stack = | 360 int argument_slots_on_stack = |
528 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); | 361 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); |
529 __ EnterApiExitFrame(argument_slots_on_stack); | 362 __ EnterApiExitFrame(argument_slots_on_stack); |
530 | 363 |
531 // Argument 9: Pass current isolate address. | 364 // Argument 9: Pass current isolate address. |
532 __ LoadAddress(kScratchRegister, | 365 __ LoadAddress(kScratchRegister, |
533 ExternalReference::isolate_address(isolate())); | 366 ExternalReference::isolate_address(isolate())); |
534 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kRegisterSize), | 367 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kRegisterSize), |
535 kScratchRegister); | 368 kScratchRegister); |
536 | 369 |
537 // Argument 8: Indicate that this is a direct call from JavaScript. | 370 // Argument 8: Indicate that this is a direct call from JavaScript. |
538 __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kRegisterSize), | 371 __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kRegisterSize), |
539 Immediate(1)); | 372 Immediate(1)); |
540 | 373 |
541 // Argument 7: Start (high end) of backtracking stack memory area. | 374 // Argument 7: Start (high end) of backtracking stack memory area. |
| 375 ExternalReference address_of_regexp_stack_memory_address = |
| 376 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
| 377 ExternalReference address_of_regexp_stack_memory_size = |
| 378 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
542 __ Move(kScratchRegister, address_of_regexp_stack_memory_address); | 379 __ Move(kScratchRegister, address_of_regexp_stack_memory_address); |
543 __ movp(r9, Operand(kScratchRegister, 0)); | 380 __ movp(r12, Operand(kScratchRegister, 0)); |
544 __ Move(kScratchRegister, address_of_regexp_stack_memory_size); | 381 __ Move(kScratchRegister, address_of_regexp_stack_memory_size); |
545 __ addp(r9, Operand(kScratchRegister, 0)); | 382 __ addp(r12, Operand(kScratchRegister, 0)); |
546 __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r9); | 383 __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r12); |
547 | 384 |
548 // Argument 6: Set the number of capture registers to zero to force global | 385 // Argument 6: Set the number of capture registers to zero to force global |
549 // regexps to behave as non-global. This does not affect non-global regexps. | 386 // regexps to behave as non-global. This does not affect non-global regexps. |
550 // Argument 6 is passed in r9 on Linux and on the stack on Windows. | 387 // Argument 6 is passed in r9 on Linux and on the stack on Windows. |
551 #ifdef _WIN64 | 388 #ifdef _WIN64 |
552 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kRegisterSize), | 389 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kRegisterSize), |
553 Immediate(0)); | 390 Immediate(0)); |
554 #else | 391 #else |
555 __ Set(r9, 0); | 392 __ Set(r9, 0); |
556 #endif | 393 #endif |
557 | 394 |
558 // Argument 5: static offsets vector buffer. | 395 // Argument 5: static offsets vector buffer. |
| 396 // Argument 5 passed in r8 on Linux and on the stack on Windows. |
| 397 #ifdef _WIN64 |
| 398 __ LoadAddress( |
| 399 r12, ExternalReference::address_of_static_offsets_vector(isolate())); |
| 400 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r12); |
| 401 #else // _WIN64 |
559 __ LoadAddress( | 402 __ LoadAddress( |
560 r8, ExternalReference::address_of_static_offsets_vector(isolate())); | 403 r8, ExternalReference::address_of_static_offsets_vector(isolate())); |
561 // Argument 5 passed in r8 on Linux and on the stack on Windows. | |
562 #ifdef _WIN64 | |
563 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8); | |
564 #endif | 404 #endif |
565 | 405 |
566 // rdi: subject string | |
567 // rbx: previous index | |
568 // rcx: encoding of subject string (1 if one_byte 0 if two_byte); | |
569 // r11: code | |
570 // r14: slice offset | |
571 // r15: original subject string | |
572 | |
573 // Argument 2: Previous index. | 406 // Argument 2: Previous index. |
574 __ movp(arg_reg_2, rbx); | 407 // TODO(jgruber): Ideally, LastIndexRegister would already equal arg_reg_2, |
| 408 // but that makes register allocation fail. |
| 409 __ movp(arg_reg_2, RegExpExecDescriptor::LastIndexRegister()); |
575 | 410 |
576 // Argument 4: End of string data | 411 // Argument 4: End of string data |
577 // Argument 3: Start of string data | 412 // Argument 3: Start of string data |
578 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; | 413 CHECK(arg_reg_4.is(RegExpExecDescriptor::StringEndRegister())); |
579 // Prepare start and end index of the input. | 414 CHECK(arg_reg_3.is(RegExpExecDescriptor::StringStartRegister())); |
580 // Load the length from the original sliced string if that is the case. | |
581 __ addp(rbx, r14); | |
582 __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset)); | |
583 __ addp(r14, arg_reg_3); // Using arg3 as scratch. | |
584 | |
585 // rbx: start index of the input | |
586 // r14: end index of the input | |
587 // r15: original subject string | |
588 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. | |
589 __ j(zero, &setup_two_byte, Label::kNear); | |
590 __ leap(arg_reg_4, | |
591 FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); | |
592 __ leap(arg_reg_3, | |
593 FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); | |
594 __ jmp(&setup_rest, Label::kNear); | |
595 __ bind(&setup_two_byte); | |
596 __ leap(arg_reg_4, | |
597 FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); | |
598 __ leap(arg_reg_3, | |
599 FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); | |
600 __ bind(&setup_rest); | |
601 | 415 |
602 // Argument 1: Original subject string. | 416 // Argument 1: Original subject string. |
603 // The original subject is in the previous stack frame. Therefore we have to | 417 CHECK(arg_reg_1.is(RegExpExecDescriptor::StringRegister())); |
604 // use rbp, which points exactly to one pointer size below the previous rsp. | |
605 // (Because creating a new stack frame pushes the previous rbp onto the stack | |
606 // and thereby moves up rsp by one kPointerSize.) | |
607 __ movp(arg_reg_1, r15); | |
608 | 418 |
609 // Locate the code entry and call it. | 419 __ addp(RegExpExecDescriptor::CodeRegister(), |
610 __ addp(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 420 Immediate(Code::kHeaderSize - kHeapObjectTag)); |
611 __ call(r11); | 421 __ call(RegExpExecDescriptor::CodeRegister()); |
612 | 422 |
613 __ LeaveApiExitFrame(true); | 423 __ LeaveApiExitFrame(true); |
614 | 424 |
615 // Check the result. | 425 // TODO(jgruber): Don't tag return value once this is supported by stubs. |
616 Label success; | 426 __ Integer32ToSmi(rax, rax); |
617 Label exception; | 427 __ ret(0 * kPointerSize); |
618 __ cmpl(rax, Immediate(1)); | |
619 // We expect exactly one result since we force the called regexp to behave | |
620 // as non-global. | |
621 __ j(equal, &success, Label::kNear); | |
622 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | |
623 __ j(equal, &exception); | |
624 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | |
625 // If none of the above, it can only be retry. | |
626 // Handle that in the runtime system. | |
627 __ j(not_equal, &runtime); | |
628 | |
629 // For failure return null. | |
630 __ LoadRoot(rax, Heap::kNullValueRootIndex); | |
631 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); | |
632 | |
633 // Load RegExp data. | |
634 __ bind(&success); | |
635 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); | |
636 __ movp(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); | |
637 __ SmiToInteger32(rax, | |
638 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); | |
639 // Calculate number of capture registers (number_of_captures + 1) * 2. | |
640 __ leal(rdx, Operand(rax, rax, times_1, 2)); | |
641 | |
642 // rdx: Number of capture registers | |
643 // Check that the last match info is a FixedArray. | |
644 __ movp(rbx, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX)); | |
645 __ JumpIfSmi(rbx, &runtime); | |
646 // Check that the object has fast elements. | |
647 __ movp(rax, FieldOperand(rbx, HeapObject::kMapOffset)); | |
648 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); | |
649 __ j(not_equal, &runtime); | |
650 // Check that the last match info has space for the capture registers and the | |
651 // additional information. Ensure no overflow in add. | |
652 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | |
653 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); | |
654 __ subl(rax, Immediate(RegExpMatchInfo::kLastMatchOverhead)); | |
655 __ cmpl(rdx, rax); | |
656 __ j(greater, &runtime); | |
657 | |
658 // rbx: last_match_info (FixedArray) | |
659 // rdx: number of capture registers | |
660 // Store the capture count. | |
661 __ Integer32ToSmi(kScratchRegister, rdx); | |
662 __ movp(FieldOperand(rbx, RegExpMatchInfo::kNumberOfCapturesOffset), | |
663 kScratchRegister); | |
664 // Store last subject and last input. | |
665 __ movp(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); | |
666 __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastSubjectOffset), rax); | |
667 __ movp(rcx, rax); | |
668 __ RecordWriteField(rbx, RegExpMatchInfo::kLastSubjectOffset, rax, rdi, | |
669 kDontSaveFPRegs); | |
670 __ movp(rax, rcx); | |
671 __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastInputOffset), rax); | |
672 __ RecordWriteField(rbx, RegExpMatchInfo::kLastInputOffset, rax, rdi, | |
673 kDontSaveFPRegs); | |
674 | |
675 // Get the static offsets vector filled by the native regexp code. | |
676 __ LoadAddress( | |
677 rcx, ExternalReference::address_of_static_offsets_vector(isolate())); | |
678 | |
679 // rbx: last_match_info (FixedArray) | |
680 // rcx: offsets vector | |
681 // rdx: number of capture registers | |
682 Label next_capture, done; | |
683 // Capture register counter starts from number of capture registers and | |
684 // counts down until wrapping after zero. | |
685 __ bind(&next_capture); | |
686 __ subp(rdx, Immediate(1)); | |
687 __ j(negative, &done, Label::kNear); | |
688 // Read the value from the static offsets vector buffer and make it a smi. | |
689 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | |
690 __ Integer32ToSmi(rdi, rdi); | |
691 // Store the smi value in the last match info. | |
692 __ movp(FieldOperand(rbx, rdx, times_pointer_size, | |
693 RegExpMatchInfo::kFirstCaptureOffset), | |
694 rdi); | |
695 __ jmp(&next_capture); | |
696 __ bind(&done); | |
697 | |
698 // Return last match info. | |
699 __ movp(rax, rbx); | |
700 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); | |
701 | |
702 __ bind(&exception); | |
703 // Result must now be exception. If there is no pending exception already a | |
704 // stack overflow (on the backtrack stack) was detected in RegExp code but | |
705 // haven't created the exception yet. Handle that in the runtime system. | |
706 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | |
707 ExternalReference pending_exception_address( | |
708 Isolate::kPendingExceptionAddress, isolate()); | |
709 Operand pending_exception_operand = | |
710 masm->ExternalOperand(pending_exception_address, rbx); | |
711 __ movp(rax, pending_exception_operand); | |
712 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | |
713 __ cmpp(rax, rdx); | |
714 __ j(equal, &runtime); | |
715 | |
716 // For exception, throw the exception again. | |
717 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
718 | |
719 // Do the runtime call to execute the regexp. | |
720 __ bind(&runtime); | |
721 __ TailCallRuntime(Runtime::kRegExpExec); | |
722 | |
723 // Deferred code for string handling. | |
724 // (6) Long external string? If not, go to (10). | |
725 __ bind(¬_seq_nor_cons); | |
726 // Compare flags are still set from (3). | |
727 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). | |
728 | |
729 // (7) External string. Short external strings have been ruled out. | |
730 __ bind(&external_string); | |
731 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | |
732 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
733 if (FLAG_debug_code) { | |
734 // Assert that we do not have a cons or slice (indirect strings) here. | |
735 // Sequential strings have already been ruled out. | |
736 __ testb(rbx, Immediate(kIsIndirectStringMask)); | |
737 __ Assert(zero, kExternalStringExpectedButNotFound); | |
738 } | |
739 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); | |
740 // Move the pointer so that offset-wise, it looks like a sequential string. | |
741 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
742 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
743 STATIC_ASSERT(kTwoByteStringTag == 0); | |
744 // (8) Is the external string one byte? If yes, go to (5). | |
745 __ testb(rbx, Immediate(kStringEncodingMask)); | |
746 __ j(not_zero, &seq_one_byte_string); // Go to (5). | |
747 | |
748 // rdi: subject string (flat two-byte) | |
749 // rax: RegExp data (FixedArray) | |
750 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
751 __ bind(&seq_two_byte_string); | |
752 __ movp(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | |
753 __ Set(rcx, 0); // Type is two byte. | |
754 __ jmp(&check_code); // Go to (E). | |
755 | |
756 // (10) Not a string or a short external string? If yes, bail out to runtime. | |
757 __ bind(¬_long_external); | |
758 // Catch non-string subject or short external string. | |
759 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | |
760 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); | |
761 __ j(not_zero, &runtime); | |
762 | |
763 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
764 Label thin_string; | |
765 __ cmpl(rbx, Immediate(kThinStringTag)); | |
766 __ j(equal, &thin_string, Label::kNear); | |
767 // Load offset into r14 and replace subject string with parent. | |
768 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); | |
769 __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); | |
770 __ jmp(&check_underlying); | |
771 | |
772 __ bind(&thin_string); | |
773 __ movp(rdi, FieldOperand(rdi, ThinString::kActualOffset)); | |
774 __ jmp(&check_underlying); | |
775 #endif // V8_INTERPRETED_REGEXP | 428 #endif // V8_INTERPRETED_REGEXP |
776 } | 429 } |
777 | 430 |
778 | 431 |
779 static int NegativeComparisonResult(Condition cc) { | 432 static int NegativeComparisonResult(Condition cc) { |
780 DCHECK(cc != equal); | 433 DCHECK(cc != equal); |
781 DCHECK((cc == less) || (cc == less_equal) | 434 DCHECK((cc == less) || (cc == less_equal) |
782 || (cc == greater) || (cc == greater_equal)); | 435 || (cc == greater) || (cc == greater_equal)); |
783 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 436 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
784 } | 437 } |
(...skipping 2537 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3322 kStackUnwindSpace, nullptr, return_value_operand, | 2975 kStackUnwindSpace, nullptr, return_value_operand, |
3323 NULL); | 2976 NULL); |
3324 } | 2977 } |
3325 | 2978 |
3326 #undef __ | 2979 #undef __ |
3327 | 2980 |
3328 } // namespace internal | 2981 } // namespace internal |
3329 } // namespace v8 | 2982 } // namespace v8 |
3330 | 2983 |
3331 #endif // V8_TARGET_ARCH_X64 | 2984 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |