| Index: src/x87/code-stubs-x87.cc
|
| diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc
|
| index f67aea74954c22aaa1203aef64df8ccccd063664..4ec7a45926cea302fa4af259371bdd675537ea69 100644
|
| --- a/src/x87/code-stubs-x87.cc
|
| +++ b/src/x87/code-stubs-x87.cc
|
| @@ -282,170 +282,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.
|
| - // esp[0]: return address
|
| - // esp[4]: last_match_info (expected JSArray)
|
| - // esp[8]: previous index
|
| - // esp[12]: subject string
|
| - // esp[16]: JSRegExp object
|
| -
|
| - static const int kLastMatchInfoOffset = 1 * kPointerSize;
|
| - static const int kPreviousIndexOffset = 2 * kPointerSize;
|
| - static const int kSubjectOffset = 3 * kPointerSize;
|
| - static const int kJSRegExpOffset = 4 * kPointerSize;
|
| -
|
| - Label runtime;
|
| - Factory* factory = isolate()->factory();
|
| -
|
| - // 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());
|
| - __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
|
| - __ test(ebx, ebx);
|
| - __ j(zero, &runtime);
|
| -
|
| - // Check that the first argument is a JSRegExp object.
|
| - __ mov(eax, Operand(esp, kJSRegExpOffset));
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - __ JumpIfSmi(eax, &runtime);
|
| - __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
|
| - __ j(not_equal, &runtime);
|
| -
|
| - // Check that the RegExp has been compiled (data contains a fixed array).
|
| - __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
|
| - if (FLAG_debug_code) {
|
| - __ test(ecx, Immediate(kSmiTagMask));
|
| - __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected);
|
| - __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
|
| - __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
|
| - }
|
| -
|
| - // ecx: RegExp data (FixedArray)
|
| - // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
|
| - __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
|
| - __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
|
| - __ j(not_equal, &runtime);
|
| -
|
| - // ecx: RegExp data (FixedArray)
|
| - // Check that the number of captures fit in the static offsets vector buffer.
|
| - __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
|
| - // Check (number_of_captures + 1) * 2 <= offsets vector size
|
| - // Or number_of_captures * 2 <= offsets vector size - 2
|
| - // Multiplying by 2 comes for free since edx is smi-tagged.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
|
| - STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
|
| - __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
|
| - __ j(above, &runtime);
|
| -
|
| - // Reset offset for possibly sliced string.
|
| - __ Move(edi, Immediate(0));
|
| - __ mov(eax, Operand(esp, kSubjectOffset));
|
| - __ JumpIfSmi(eax, &runtime);
|
| - __ mov(edx, eax); // Make a copy of the original subject string.
|
| -
|
| - // eax: subject string
|
| - // edx: subject string
|
| - // ecx: RegExp data (FixedArray)
|
| - // 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);
|
| - // (1) Sequential two byte? If yes, go to (9).
|
| - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
|
| -
|
| - __ and_(ebx, 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.
|
| - __ and_(ebx, 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);
|
| - __ cmp(ebx, 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.
|
| - __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
|
| - __ j(not_equal, &runtime);
|
| - __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
|
| - __ jmp(&check_underlying);
|
| -
|
| - // eax: sequential subject string (or look-alike, external string)
|
| - // edx: original subject string
|
| - // ecx: RegExp data (FixedArray)
|
| - // (5) One byte sequential. Load regexp code for one byte.
|
| - __ bind(&seq_one_byte_string);
|
| - // Load previous index and check range before edx is overwritten. We have
|
| - // to use edx instead of eax here because it might have been only made to
|
| - // look like a sequential string when it actually is an external string.
|
| - __ mov(ebx, Operand(esp, kPreviousIndexOffset));
|
| - __ JumpIfNotSmi(ebx, &runtime);
|
| - __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
|
| - __ j(above_equal, &runtime);
|
| - __ mov(edx, FieldOperand(ecx, JSRegExp::kDataOneByteCodeOffset));
|
| - __ Move(ecx, Immediate(1)); // Type is one byte.
|
| -
|
| - // (E) Carry on. String handling is done.
|
| - __ bind(&check_code);
|
| - // edx: 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
|
| - // a smi (code flushing support).
|
| - __ JumpIfSmi(edx, &runtime);
|
| -
|
| - // eax: subject string
|
| - // ebx: previous index (smi)
|
| - // edx: code
|
| - // ecx: encoding of subject string (1 if one_byte, 0 if two_byte);
|
| - // 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;
|
| __ EnterApiExitFrame(kRegExpExecuteArguments);
|
| @@ -458,6 +298,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
|
| __ mov(Operand(esp, 7 * kPointerSize), 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());
|
| __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
|
| __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
|
| __ mov(Operand(esp, 6 * kPointerSize), esi);
|
| @@ -471,228 +315,32 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
|
| Immediate(ExternalReference::address_of_static_offsets_vector(
|
| isolate())));
|
|
|
| - // Argument 2: Previous index.
|
| - __ SmiUntag(ebx);
|
| - __ mov(Operand(esp, 1 * kPointerSize), ebx);
|
| -
|
| - // Argument 1: Original subject string.
|
| - // The original subject is in the previous stack frame. Therefore we have to
|
| - // use ebp, which points exactly to one pointer size below the previous esp.
|
| - // (Because creating a new stack frame pushes the previous ebp onto the stack
|
| - // and thereby moves up esp by one kPointerSize.)
|
| - __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
|
| - __ mov(Operand(esp, 0 * kPointerSize), esi);
|
| -
|
| - // esi: original subject string
|
| - // eax: underlying subject string
|
| - // ebx: previous index
|
| - // ecx: encoding of subject string (1 if one_byte 0 if two_byte);
|
| - // edx: code
|
| // Argument 4: End of string data
|
| // Argument 3: Start of string data
|
| - // Prepare start and end index of the input.
|
| - // Load the length from the original sliced string if that is the case.
|
| - __ mov(esi, FieldOperand(esi, String::kLengthOffset));
|
| - __ add(esi, edi); // Calculate input end wrt offset.
|
| - __ SmiUntag(edi);
|
| - __ add(ebx, edi); // Calculate input start wrt offset.
|
| -
|
| - // ebx: start index of the input string
|
| - // esi: end index of the input string
|
| - Label setup_two_byte, setup_rest;
|
| - __ test(ecx, ecx);
|
| - __ j(zero, &setup_two_byte, Label::kNear);
|
| - __ SmiUntag(esi);
|
| - __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize));
|
| - __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
|
| - __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize));
|
| - __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
|
| - __ jmp(&setup_rest, Label::kNear);
|
| -
|
| - __ bind(&setup_two_byte);
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2).
|
| - __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
|
| - __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
|
| - __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
|
| - __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
|
| + __ mov(Operand(esp, 3 * kPointerSize),
|
| + RegExpExecDescriptor::StringEndRegister());
|
| + __ mov(Operand(esp, 2 * kPointerSize),
|
| + RegExpExecDescriptor::StringStartRegister());
|
| +
|
| + // Argument 2: Previous index.
|
| + __ mov(Operand(esp, 1 * kPointerSize),
|
| + RegExpExecDescriptor::LastIndexRegister());
|
|
|
| - __ bind(&setup_rest);
|
| + // Argument 1: Original subject string.
|
| + __ mov(Operand(esp, 0 * kPointerSize),
|
| + RegExpExecDescriptor::StringRegister());
|
|
|
| // Locate the code entry and call it.
|
| - __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
| - __ call(edx);
|
| + __ add(RegExpExecDescriptor::CodeRegister(),
|
| + Immediate(Code::kHeaderSize - kHeapObjectTag));
|
| + __ call(RegExpExecDescriptor::CodeRegister());
|
|
|
| // Drop arguments and come back to JS mode.
|
| __ LeaveApiExitFrame(true);
|
|
|
| - // Check the result.
|
| - Label success;
|
| - __ cmp(eax, 1);
|
| - // We expect exactly one result since we force the called regexp to behave
|
| - // as non-global.
|
| - __ j(equal, &success);
|
| - Label failure;
|
| - __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
|
| - __ j(equal, &failure);
|
| - __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
|
| - // If not exception it can only be retry. Handle that in the runtime system.
|
| - __ j(not_equal, &runtime);
|
| - // 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(Isolate::kPendingExceptionAddress,
|
| - isolate());
|
| - __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
|
| - __ mov(eax, Operand::StaticVariable(pending_exception));
|
| - __ cmp(edx, eax);
|
| - __ j(equal, &runtime);
|
| -
|
| - // For exception, throw the exception again.
|
| - __ TailCallRuntime(Runtime::kRegExpExecReThrow);
|
| -
|
| - __ bind(&failure);
|
| - // For failure to match, return null.
|
| - __ mov(eax, factory->null_value());
|
| - __ ret(4 * kPointerSize);
|
| -
|
| - // Load RegExp data.
|
| - __ bind(&success);
|
| - __ mov(eax, Operand(esp, kJSRegExpOffset));
|
| - __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
|
| - __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
|
| - // Calculate number of capture registers (number_of_captures + 1) * 2.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
|
| - __ add(edx, Immediate(2)); // edx was a smi.
|
| -
|
| - // edx: Number of capture registers
|
| - // Check that the last match info is a FixedArray.
|
| - __ mov(ebx, Operand(esp, kLastMatchInfoOffset));
|
| - __ JumpIfSmi(ebx, &runtime);
|
| - // Check that the object has fast elements.
|
| - __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
|
| - __ cmp(eax, factory->fixed_array_map());
|
| - __ j(not_equal, &runtime);
|
| - // Check that the last match info has space for the capture registers and the
|
| - // additional information.
|
| - __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
|
| - __ SmiUntag(eax);
|
| - __ sub(eax, Immediate(RegExpMatchInfo::kLastMatchOverhead));
|
| - __ cmp(edx, eax);
|
| - __ j(greater, &runtime);
|
| -
|
| - // ebx: last_match_info backing store (FixedArray)
|
| - // edx: number of capture registers
|
| - // Store the capture count.
|
| - __ SmiTag(edx); // Number of capture registers to smi.
|
| - __ mov(FieldOperand(ebx, RegExpMatchInfo::kNumberOfCapturesOffset), edx);
|
| - __ SmiUntag(edx); // Number of capture registers back from smi.
|
| - // Store last subject and last input.
|
| - __ mov(eax, Operand(esp, kSubjectOffset));
|
| - __ mov(ecx, eax);
|
| - __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastSubjectOffset), eax);
|
| - __ RecordWriteField(ebx, RegExpMatchInfo::kLastSubjectOffset, eax, edi,
|
| - kDontSaveFPRegs);
|
| - __ mov(eax, ecx);
|
| - __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastInputOffset), eax);
|
| - __ RecordWriteField(ebx, RegExpMatchInfo::kLastInputOffset, eax, edi,
|
| - kDontSaveFPRegs);
|
| -
|
| - // Get the static offsets vector filled by the native regexp code.
|
| - ExternalReference address_of_static_offsets_vector =
|
| - ExternalReference::address_of_static_offsets_vector(isolate());
|
| - __ mov(ecx, Immediate(address_of_static_offsets_vector));
|
| -
|
| - // ebx: last_match_info backing store (FixedArray)
|
| - // ecx: offsets vector
|
| - // edx: 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);
|
| - __ sub(edx, Immediate(1));
|
| - __ j(negative, &done, Label::kNear);
|
| - // Read the value from the static offsets vector buffer.
|
| - __ mov(edi, Operand(ecx, edx, times_int_size, 0));
|
| - __ SmiTag(edi);
|
| - // Store the smi value in the last match info.
|
| - __ mov(FieldOperand(ebx, edx, times_pointer_size,
|
| - RegExpMatchInfo::kFirstCaptureOffset),
|
| - edi);
|
| - __ jmp(&next_capture);
|
| - __ bind(&done);
|
| -
|
| - // Return last match info.
|
| - __ mov(eax, ebx);
|
| - __ ret(4 * kPointerSize);
|
| -
|
| - // 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);
|
| - // Reload instance type.
|
| - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - __ movzx_b(ebx, FieldOperand(ebx, 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.
|
| - __ test_b(ebx, Immediate(kIsIndirectStringMask));
|
| - __ Assert(zero, kExternalStringExpectedButNotFound);
|
| - }
|
| - __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
|
| - // Move the pointer so that offset-wise, it looks like a sequential string.
|
| - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
|
| - __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
|
| - STATIC_ASSERT(kTwoByteStringTag == 0);
|
| - // (8) Is the external string one byte? If yes, go to (5).
|
| - __ test_b(ebx, Immediate(kStringEncodingMask));
|
| - __ j(not_zero, &seq_one_byte_string); // Go to (5).
|
| -
|
| - // eax: sequential subject string (or look-alike, external string)
|
| - // edx: original subject string
|
| - // ecx: RegExp data (FixedArray)
|
| - // (9) Two byte sequential. Load regexp code for two byte. Go to (E).
|
| - __ bind(&seq_two_byte_string);
|
| - // Load previous index and check range before edx is overwritten. We have
|
| - // to use edx instead of eax here because it might have been only made to
|
| - // look like a sequential string when it actually is an external string.
|
| - __ mov(ebx, Operand(esp, kPreviousIndexOffset));
|
| - __ JumpIfNotSmi(ebx, &runtime);
|
| - __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
|
| - __ j(above_equal, &runtime);
|
| - __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
|
| - __ Move(ecx, Immediate(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);
|
| - __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
|
| - __ j(not_zero, &runtime);
|
| -
|
| - // (11) Sliced or thin string. Replace subject with parent. Go to (1).
|
| - Label thin_string;
|
| - __ cmp(ebx, Immediate(kThinStringTag));
|
| - __ j(equal, &thin_string, Label::kNear);
|
| - // Load offset into edi and replace subject string with parent.
|
| - __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
|
| - __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
|
| - __ jmp(&check_underlying); // Go to (1).
|
| -
|
| - __ bind(&thin_string);
|
| - __ mov(eax, FieldOperand(eax, ThinString::kActualOffset));
|
| - __ jmp(&check_underlying); // Go to (1).
|
| + // TODO(jgruber): Don't tag return value once this is supported by stubs.
|
| + __ SmiTag(eax);
|
| + __ ret(0 * kPointerSize);
|
| #endif // V8_INTERPRETED_REGEXP
|
| }
|
|
|
|
|