Index: src/x64/code-stubs-x64.cc |
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc |
index 7b57c2cd19e73f7c74b0689a69a5f234d396cda1..fc080f4c4cc2fc63abbf122d7d4f4e23b903892d 100644 |
--- a/src/x64/code-stubs-x64.cc |
+++ b/src/x64/code-stubs-x64.cc |
@@ -351,177 +351,10 @@ void MathPowStub::Generate(MacroAssembler* masm) { |
} |
void RegExpExecStub::Generate(MacroAssembler* masm) { |
- // Just jump directly to runtime if native RegExp is not selected at compile |
- // time or if regexp entry in generated code is turned off runtime switch or |
- // at compilation. |
#ifdef V8_INTERPRETED_REGEXP |
- __ TailCallRuntime(Runtime::kRegExpExec); |
+ // This case is handled prior to the RegExpExecStub call. |
+ __ Abort(kUnexpectedRegExpExecCall); |
#else // V8_INTERPRETED_REGEXP |
- |
- // Stack frame on entry. |
- // rsp[0] : return address |
- // rsp[8] : last_match_info (expected JSArray) |
- // rsp[16] : previous index |
- // rsp[24] : subject string |
- // rsp[32] : JSRegExp object |
- |
- enum RegExpExecStubArgumentIndices { |
- JS_REG_EXP_OBJECT_ARGUMENT_INDEX, |
- SUBJECT_STRING_ARGUMENT_INDEX, |
- PREVIOUS_INDEX_ARGUMENT_INDEX, |
- LAST_MATCH_INFO_ARGUMENT_INDEX, |
- REG_EXP_EXEC_ARGUMENT_COUNT |
- }; |
- |
- StackArgumentsAccessor args(rsp, REG_EXP_EXEC_ARGUMENT_COUNT, |
- ARGUMENTS_DONT_CONTAIN_RECEIVER); |
- Label runtime; |
- // Ensure that a RegExp stack is allocated. |
- ExternalReference address_of_regexp_stack_memory_address = |
- ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
- ExternalReference address_of_regexp_stack_memory_size = |
- ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
- __ Load(kScratchRegister, address_of_regexp_stack_memory_size); |
- __ testp(kScratchRegister, kScratchRegister); |
- __ j(zero, &runtime); |
- |
- // Check that the first argument is a JSRegExp object. |
- __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
- __ JumpIfSmi(rax, &runtime); |
- __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); |
- __ j(not_equal, &runtime); |
- |
- // Check that the RegExp has been compiled (data contains a fixed array). |
- __ movp(rax, FieldOperand(rax, JSRegExp::kDataOffset)); |
- if (FLAG_debug_code) { |
- Condition is_smi = masm->CheckSmi(rax); |
- __ Check(NegateCondition(is_smi), |
- kUnexpectedTypeForRegExpDataFixedArrayExpected); |
- __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); |
- __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); |
- } |
- |
- // rax: RegExp data (FixedArray) |
- // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
- __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); |
- __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); |
- __ j(not_equal, &runtime); |
- |
- // rax: RegExp data (FixedArray) |
- // Check that the number of captures fit in the static offsets vector buffer. |
- __ SmiToInteger32(rdx, |
- FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); |
- // Check (number_of_captures + 1) * 2 <= offsets vector size |
- // Or number_of_captures <= offsets vector size / 2 - 1 |
- STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
- __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); |
- __ j(above, &runtime); |
- |
- // Reset offset for possibly sliced string. |
- __ Set(r14, 0); |
- __ movp(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
- __ JumpIfSmi(rdi, &runtime); |
- __ movp(r15, rdi); // Make a copy of the original subject string. |
- // rax: RegExp data (FixedArray) |
- // rdi: subject string |
- // r15: subject string |
- // Handle subject string according to its encoding and representation: |
- // (1) Sequential two byte? If yes, go to (9). |
- // (2) Sequential one byte? If yes, go to (5). |
- // (3) Sequential or cons? If not, go to (6). |
- // (4) Cons string. If the string is flat, replace subject with first string |
- // and go to (1). Otherwise bail out to runtime. |
- // (5) One byte sequential. Load regexp code for one byte. |
- // (E) Carry on. |
- /// [...] |
- |
- // Deferred code at the end of the stub: |
- // (6) Long external string? If not, go to (10). |
- // (7) External string. Make it, offset-wise, look like a sequential string. |
- // (8) Is the external string one byte? If yes, go to (5). |
- // (9) Two byte sequential. Load regexp code for two byte. Go to (E). |
- // (10) Short external string or not a string? If yes, bail out to runtime. |
- // (11) Sliced or thin string. Replace subject with parent. Go to (1). |
- |
- Label seq_one_byte_string /* 5 */, seq_two_byte_string /* 9 */, |
- external_string /* 7 */, check_underlying /* 1 */, |
- not_seq_nor_cons /* 6 */, check_code /* E */, not_long_external /* 10 */; |
- |
- __ bind(&check_underlying); |
- __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
- __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
- |
- // (1) Sequential two byte? If yes, go to (9). |
- __ andb(rbx, Immediate(kIsNotStringMask | |
- kStringRepresentationMask | |
- kStringEncodingMask | |
- kShortExternalStringMask)); |
- STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
- __ j(zero, &seq_two_byte_string); // Go to (9). |
- |
- // (2) Sequential one byte? If yes, go to (5). |
- // Any other sequential string must be one byte. |
- __ andb(rbx, Immediate(kIsNotStringMask | |
- kStringRepresentationMask | |
- kShortExternalStringMask)); |
- __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (5). |
- |
- // (3) Sequential or cons? If not, go to (6). |
- // We check whether the subject string is a cons, since sequential strings |
- // have already been covered. |
- STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
- STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
- STATIC_ASSERT(kThinStringTag > kExternalStringTag); |
- STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); |
- STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); |
- __ cmpp(rbx, Immediate(kExternalStringTag)); |
- __ j(greater_equal, ¬_seq_nor_cons); // Go to (6). |
- |
- // (4) Cons string. Check that it's flat. |
- // Replace subject with first string and reload instance type. |
- __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
- Heap::kempty_stringRootIndex); |
- __ j(not_equal, &runtime); |
- __ movp(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
- __ jmp(&check_underlying); |
- |
- // (5) One byte sequential. Load regexp code for one byte. |
- __ bind(&seq_one_byte_string); |
- // rax: RegExp data (FixedArray) |
- __ movp(r11, FieldOperand(rax, JSRegExp::kDataOneByteCodeOffset)); |
- __ Set(rcx, 1); // Type is one byte. |
- |
- // (E) Carry on. String handling is done. |
- __ bind(&check_code); |
- // r11: irregexp code |
- // Check that the irregexp code has been generated for the actual string |
- // encoding. If it has, the field contains a code object otherwise it contains |
- // smi (code flushing support) |
- __ JumpIfSmi(r11, &runtime); |
- |
- // rdi: sequential subject string (or look-alike, external string) |
- // r15: original subject string |
- // rcx: encoding of subject string (1 if one_byte, 0 if two_byte); |
- // r11: code |
- // Load used arguments before starting to push arguments for call to native |
- // RegExp code to avoid handling changing stack height. |
- // We have to use r15 instead of rdi to load the length because rdi might |
- // have been only made to look like a sequential string when it actually |
- // is an external string. |
- __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); |
- __ JumpIfNotSmi(rbx, &runtime); |
- __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); |
- __ j(above_equal, &runtime); |
- __ SmiToInteger64(rbx, rbx); |
- |
- // rdi: subject string |
- // rbx: previous index |
- // rcx: encoding of subject string (1 if one_byte 0 if two_byte); |
- // r11: code |
- // All checks done. Now push arguments for native regexp code. |
- Counters* counters = isolate()->counters(); |
- __ IncrementCounter(counters->regexp_entry_native(), 1); |
- |
// Isolates: note we add an additional parameter here (isolate pointer). |
static const int kRegExpExecuteArguments = 9; |
int argument_slots_on_stack = |
@@ -539,11 +372,15 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { |
Immediate(1)); |
// Argument 7: Start (high end) of backtracking stack memory area. |
+ ExternalReference address_of_regexp_stack_memory_address = |
+ ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
+ ExternalReference address_of_regexp_stack_memory_size = |
+ ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
__ Move(kScratchRegister, address_of_regexp_stack_memory_address); |
- __ movp(r9, Operand(kScratchRegister, 0)); |
+ __ movp(r12, Operand(kScratchRegister, 0)); |
__ Move(kScratchRegister, address_of_regexp_stack_memory_size); |
- __ addp(r9, Operand(kScratchRegister, 0)); |
- __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r9); |
+ __ addp(r12, Operand(kScratchRegister, 0)); |
+ __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r12); |
// Argument 6: Set the number of capture registers to zero to force global |
// regexps to behave as non-global. This does not affect non-global regexps. |
@@ -556,222 +393,38 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { |
#endif |
// Argument 5: static offsets vector buffer. |
- __ LoadAddress( |
- r8, ExternalReference::address_of_static_offsets_vector(isolate())); |
// Argument 5 passed in r8 on Linux and on the stack on Windows. |
#ifdef _WIN64 |
- __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8); |
+ __ LoadAddress( |
+ r12, ExternalReference::address_of_static_offsets_vector(isolate())); |
+ __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r12); |
+#else // _WIN64 |
+ __ LoadAddress( |
+ r8, ExternalReference::address_of_static_offsets_vector(isolate())); |
#endif |
- // rdi: subject string |
- // rbx: previous index |
- // rcx: encoding of subject string (1 if one_byte 0 if two_byte); |
- // r11: code |
- // r14: slice offset |
- // r15: original subject string |
- |
// Argument 2: Previous index. |
- __ movp(arg_reg_2, rbx); |
+ // TODO(jgruber): Ideally, LastIndexRegister would already equal arg_reg_2, |
+ // but that makes register allocation fail. |
+ __ movp(arg_reg_2, RegExpExecDescriptor::LastIndexRegister()); |
// Argument 4: End of string data |
// Argument 3: Start of string data |
- Label setup_two_byte, setup_rest, got_length, length_not_from_slice; |
- // Prepare start and end index of the input. |
- // Load the length from the original sliced string if that is the case. |
- __ addp(rbx, r14); |
- __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset)); |
- __ addp(r14, arg_reg_3); // Using arg3 as scratch. |
- |
- // rbx: start index of the input |
- // r14: end index of the input |
- // r15: original subject string |
- __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. |
- __ j(zero, &setup_two_byte, Label::kNear); |
- __ leap(arg_reg_4, |
- FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); |
- __ leap(arg_reg_3, |
- FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); |
- __ jmp(&setup_rest, Label::kNear); |
- __ bind(&setup_two_byte); |
- __ leap(arg_reg_4, |
- FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); |
- __ leap(arg_reg_3, |
- FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
- __ bind(&setup_rest); |
+ CHECK(arg_reg_4.is(RegExpExecDescriptor::StringEndRegister())); |
+ CHECK(arg_reg_3.is(RegExpExecDescriptor::StringStartRegister())); |
// Argument 1: Original subject string. |
- // The original subject is in the previous stack frame. Therefore we have to |
- // use rbp, which points exactly to one pointer size below the previous rsp. |
- // (Because creating a new stack frame pushes the previous rbp onto the stack |
- // and thereby moves up rsp by one kPointerSize.) |
- __ movp(arg_reg_1, r15); |
+ CHECK(arg_reg_1.is(RegExpExecDescriptor::StringRegister())); |
- // Locate the code entry and call it. |
- __ addp(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
- __ call(r11); |
+ __ addp(RegExpExecDescriptor::CodeRegister(), |
+ Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ __ call(RegExpExecDescriptor::CodeRegister()); |
__ LeaveApiExitFrame(true); |
- // Check the result. |
- Label success; |
- Label exception; |
- __ cmpl(rax, Immediate(1)); |
- // We expect exactly one result since we force the called regexp to behave |
- // as non-global. |
- __ j(equal, &success, Label::kNear); |
- __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
- __ j(equal, &exception); |
- __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
- // If none of the above, it can only be retry. |
- // Handle that in the runtime system. |
- __ j(not_equal, &runtime); |
- |
- // For failure return null. |
- __ LoadRoot(rax, Heap::kNullValueRootIndex); |
- __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
- |
- // Load RegExp data. |
- __ bind(&success); |
- __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
- __ movp(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); |
- __ SmiToInteger32(rax, |
- FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); |
- // Calculate number of capture registers (number_of_captures + 1) * 2. |
- __ leal(rdx, Operand(rax, rax, times_1, 2)); |
- |
- // rdx: Number of capture registers |
- // Check that the last match info is a FixedArray. |
- __ movp(rbx, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX)); |
- __ JumpIfSmi(rbx, &runtime); |
- // Check that the object has fast elements. |
- __ movp(rax, FieldOperand(rbx, HeapObject::kMapOffset)); |
- __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); |
- __ j(not_equal, &runtime); |
- // Check that the last match info has space for the capture registers and the |
- // additional information. Ensure no overflow in add. |
- STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
- __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); |
- __ subl(rax, Immediate(RegExpMatchInfo::kLastMatchOverhead)); |
- __ cmpl(rdx, rax); |
- __ j(greater, &runtime); |
- |
- // rbx: last_match_info (FixedArray) |
- // rdx: number of capture registers |
- // Store the capture count. |
- __ Integer32ToSmi(kScratchRegister, rdx); |
- __ movp(FieldOperand(rbx, RegExpMatchInfo::kNumberOfCapturesOffset), |
- kScratchRegister); |
- // Store last subject and last input. |
- __ movp(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
- __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastSubjectOffset), rax); |
- __ movp(rcx, rax); |
- __ RecordWriteField(rbx, RegExpMatchInfo::kLastSubjectOffset, rax, rdi, |
- kDontSaveFPRegs); |
- __ movp(rax, rcx); |
- __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastInputOffset), rax); |
- __ RecordWriteField(rbx, RegExpMatchInfo::kLastInputOffset, rax, rdi, |
- kDontSaveFPRegs); |
- |
- // Get the static offsets vector filled by the native regexp code. |
- __ LoadAddress( |
- rcx, ExternalReference::address_of_static_offsets_vector(isolate())); |
- |
- // rbx: last_match_info (FixedArray) |
- // rcx: offsets vector |
- // rdx: number of capture registers |
- Label next_capture, done; |
- // Capture register counter starts from number of capture registers and |
- // counts down until wrapping after zero. |
- __ bind(&next_capture); |
- __ subp(rdx, Immediate(1)); |
- __ j(negative, &done, Label::kNear); |
- // Read the value from the static offsets vector buffer and make it a smi. |
- __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
- __ Integer32ToSmi(rdi, rdi); |
- // Store the smi value in the last match info. |
- __ movp(FieldOperand(rbx, rdx, times_pointer_size, |
- RegExpMatchInfo::kFirstCaptureOffset), |
- rdi); |
- __ jmp(&next_capture); |
- __ bind(&done); |
- |
- // Return last match info. |
- __ movp(rax, rbx); |
- __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
- |
- __ bind(&exception); |
- // Result must now be exception. If there is no pending exception already a |
- // stack overflow (on the backtrack stack) was detected in RegExp code but |
- // haven't created the exception yet. Handle that in the runtime system. |
- // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
- ExternalReference pending_exception_address( |
- Isolate::kPendingExceptionAddress, isolate()); |
- Operand pending_exception_operand = |
- masm->ExternalOperand(pending_exception_address, rbx); |
- __ movp(rax, pending_exception_operand); |
- __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
- __ cmpp(rax, rdx); |
- __ j(equal, &runtime); |
- |
- // For exception, throw the exception again. |
- __ TailCallRuntime(Runtime::kRegExpExecReThrow); |
- |
- // Do the runtime call to execute the regexp. |
- __ bind(&runtime); |
- __ TailCallRuntime(Runtime::kRegExpExec); |
- |
- // Deferred code for string handling. |
- // (6) Long external string? If not, go to (10). |
- __ bind(¬_seq_nor_cons); |
- // Compare flags are still set from (3). |
- __ j(greater, ¬_long_external, Label::kNear); // Go to (10). |
- |
- // (7) External string. Short external strings have been ruled out. |
- __ bind(&external_string); |
- __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
- __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
- if (FLAG_debug_code) { |
- // Assert that we do not have a cons or slice (indirect strings) here. |
- // Sequential strings have already been ruled out. |
- __ testb(rbx, Immediate(kIsIndirectStringMask)); |
- __ Assert(zero, kExternalStringExpectedButNotFound); |
- } |
- __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); |
- // Move the pointer so that offset-wise, it looks like a sequential string. |
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
- __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
- STATIC_ASSERT(kTwoByteStringTag == 0); |
- // (8) Is the external string one byte? If yes, go to (5). |
- __ testb(rbx, Immediate(kStringEncodingMask)); |
- __ j(not_zero, &seq_one_byte_string); // Go to (5). |
- |
- // rdi: subject string (flat two-byte) |
- // rax: RegExp data (FixedArray) |
- // (9) Two byte sequential. Load regexp code for two byte. Go to (E). |
- __ bind(&seq_two_byte_string); |
- __ movp(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
- __ Set(rcx, 0); // Type is two byte. |
- __ jmp(&check_code); // Go to (E). |
- |
- // (10) Not a string or a short external string? If yes, bail out to runtime. |
- __ bind(¬_long_external); |
- // Catch non-string subject or short external string. |
- STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); |
- __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); |
- __ j(not_zero, &runtime); |
- |
- // (11) Sliced or thin string. Replace subject with parent. Go to (1). |
- Label thin_string; |
- __ cmpl(rbx, Immediate(kThinStringTag)); |
- __ j(equal, &thin_string, Label::kNear); |
- // Load offset into r14 and replace subject string with parent. |
- __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); |
- __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); |
- __ jmp(&check_underlying); |
- |
- __ bind(&thin_string); |
- __ movp(rdi, FieldOperand(rdi, ThinString::kActualOffset)); |
- __ jmp(&check_underlying); |
+ // TODO(jgruber): Don't tag return value once this is supported by stubs. |
+ __ Integer32ToSmi(rax, rax); |
+ __ ret(0 * kPointerSize); |
#endif // V8_INTERPRETED_REGEXP |
} |