Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(947)

Unified Diff: src/ia32/code-stubs-ia32.cc

Issue 2738413002: [regexp] Port RegExpExecStub to CSA (mostly) (Closed)
Patch Set: Rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stub-assembler.cc ('k') | src/ia32/interface-descriptors-ia32.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ia32/code-stubs-ia32.cc
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 1320d90e8b9e303699b2363d76a09993307b9652..56ce2c52133bb74f5190dc857145b5b8dc014da5 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -463,170 +463,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, &not_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);
@@ -639,6 +479,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);
@@ -652,228 +496,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());
- __ bind(&setup_rest);
+ // Argument 2: Previous index.
+ __ mov(Operand(esp, 1 * kPointerSize),
+ RegExpExecDescriptor::LastIndexRegister());
+
+ // 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 (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 (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(&not_seq_nor_cons);
- // Compare flags are still set from (3).
- __ j(greater, &not_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(&not_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
}
« no previous file with comments | « src/code-stub-assembler.cc ('k') | src/ia32/interface-descriptors-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698