| 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
|
| }
|
|
|
|
|