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

Unified Diff: src/arm64/code-stubs-arm64.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/arm/interface-descriptors-arm.cc ('k') | src/arm64/interface-descriptors-arm64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm64/code-stubs-arm64.cc
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
index 000a8c30619a6a5d97cb47674fe265b9dce03e83..ec00581566f28e75819e9c2df46fa70dd5342fde 100644
--- a/src/arm64/code-stubs-arm64.cc
+++ b/src/arm64/code-stubs-arm64.cc
@@ -1269,223 +1269,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
void RegExpExecStub::Generate(MacroAssembler* masm) {
#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.
- // jssp[0]: last_match_info (expected JSArray)
- // jssp[8]: previous index
- // jssp[16]: subject string
- // jssp[24]: JSRegExp object
- Label runtime;
-
- // Use of registers for this function.
-
- // Variable registers:
- // x10-x13 used as scratch registers
- // w0 string_type type of subject string
- // x2 jsstring_length subject string length
- // x3 jsregexp_object JSRegExp object
- // w4 string_encoding Latin1 or UC16
- // w5 sliced_string_offset if the string is a SlicedString
- // offset to the underlying string
- // w6 string_representation groups attributes of the string:
- // - is a string
- // - type of the string
- // - is a short external string
- Register string_type = w0;
- Register jsstring_length = x2;
- Register jsregexp_object = x3;
- Register string_encoding = w4;
- Register sliced_string_offset = w5;
- Register string_representation = w6;
-
- // These are in callee save registers and will be preserved by the call
- // to the native RegExp code, as this code is called using the normal
- // C calling convention. When calling directly from generated code the
- // native RegExp code will not do a GC and therefore the content of
- // these registers are safe to use after the call.
-
- // x19 subject subject string
- // x20 regexp_data RegExp data (FixedArray)
- // x21 last_match_info_elements info relative to the last match
- // (FixedArray)
- // x22 code_object generated regexp code
- Register subject = x19;
- Register regexp_data = x20;
- Register last_match_info_elements = x21;
- Register code_object = x22;
-
- // Stack frame.
- // jssp[00]: last_match_info (JSArray)
- // jssp[08]: previous index
- // jssp[16]: subject string
- // jssp[24]: JSRegExp object
-
- const int kLastMatchInfoOffset = 0 * kPointerSize;
- const int kPreviousIndexOffset = 1 * kPointerSize;
- const int kSubjectOffset = 2 * kPointerSize;
- const int kJSRegExpOffset = 3 * kPointerSize;
-
- // 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(x10, address_of_regexp_stack_memory_size);
- __ Ldr(x10, MemOperand(x10));
- __ Cbz(x10, &runtime);
-
- // Check that the first argument is a JSRegExp object.
- DCHECK(jssp.Is(__ StackPointer()));
- __ Peek(jsregexp_object, kJSRegExpOffset);
- __ JumpIfSmi(jsregexp_object, &runtime);
- __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime);
-
- // Check that the RegExp has been compiled (data contains a fixed array).
- __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset));
- if (FLAG_debug_code) {
- STATIC_ASSERT(kSmiTag == 0);
- __ Tst(regexp_data, kSmiTagMask);
- __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected);
- __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE);
- __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
- }
-
- // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
- __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
- __ Cmp(x10, Smi::FromInt(JSRegExp::IRREGEXP));
- __ B(ne, &runtime);
-
- // Check that the number of captures fit in the static offsets vector buffer.
- // We have always at least one capture for the whole match, plus additional
- // ones due to capturing parentheses. A capture takes 2 registers.
- // The number of capture registers then is (number_of_captures + 1) * 2.
- __ Ldrsw(x10,
- UntagSmiFieldMemOperand(regexp_data,
- JSRegExp::kIrregexpCaptureCountOffset));
- // Check (number_of_captures + 1) * 2 <= offsets vector size
- // number_of_captures * 2 <= offsets vector size - 2
- STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
- __ Add(x10, x10, x10);
- __ Cmp(x10, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
- __ B(hi, &runtime);
-
- // Initialize offset for possibly sliced string.
- __ Mov(sliced_string_offset, 0);
-
- DCHECK(jssp.Is(__ StackPointer()));
- __ Peek(subject, kSubjectOffset);
- __ JumpIfSmi(subject, &runtime);
-
- __ Ldr(jsstring_length, FieldMemOperand(subject, String::kLengthOffset));
-
- // Handle subject string according to its encoding and representation:
- // (1) Sequential string? If yes, go to (4).
- // (2) Sequential or cons? If not, go to (5).
- // (3) Cons string. If the string is flat, replace subject with first string
- // and go to (1). Otherwise bail out to runtime.
- // (4) Sequential string. Load regexp code according to encoding.
- // (E) Carry on.
- /// [...]
-
- // Deferred code at the end of the stub:
- // (5) Long external string? If not, go to (7).
- // (6) External string. Make it, offset-wise, look like a sequential string.
- // Go to (4).
- // (7) Short external string or not a string? If yes, bail out to runtime.
- // (8) Sliced or thin string. Replace subject with parent. Go to (1).
-
- Label check_underlying; // (1)
- Label seq_string; // (4)
- Label not_seq_nor_cons; // (5)
- Label external_string; // (6)
- Label not_long_external; // (7)
-
- __ Bind(&check_underlying);
- __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
- __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
-
- // (1) Sequential string? If yes, go to (4).
- __ And(string_representation,
- string_type,
- kIsNotStringMask |
- kStringRepresentationMask |
- kShortExternalStringMask);
- // We depend on the fact that Strings of type
- // SeqString and not ShortExternalString are defined
- // by the following pattern:
- // string_type: 0XX0 XX00
- // ^ ^ ^^
- // | | ||
- // | | is a SeqString
- // | is not a short external String
- // is a String
- STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
- STATIC_ASSERT(kShortExternalStringTag != 0);
- __ Cbz(string_representation, &seq_string); // Go to (4).
-
- // (2) Sequential or cons? If not, go to (5).
- STATIC_ASSERT(kConsStringTag < kExternalStringTag);
- STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
- STATIC_ASSERT(kThinStringTag > kExternalStringTag);
- STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
- STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
- __ Cmp(string_representation, kExternalStringTag);
- __ B(ge, &not_seq_nor_cons); // Go to (5).
-
- // (3) Cons string. Check that it's flat.
- __ Ldr(x10, FieldMemOperand(subject, ConsString::kSecondOffset));
- __ JumpIfNotRoot(x10, Heap::kempty_stringRootIndex, &runtime);
- // Replace subject with first string.
- __ Ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
- __ B(&check_underlying);
-
- // (4) Sequential string. Load regexp code according to encoding.
- __ Bind(&seq_string);
-
- // Check that the third argument is a positive smi less than the subject
- // string length. A negative value will be greater (unsigned comparison).
- DCHECK(jssp.Is(__ StackPointer()));
- __ Peek(x10, kPreviousIndexOffset);
- __ JumpIfNotSmi(x10, &runtime);
- __ Cmp(jsstring_length, x10);
- __ B(ls, &runtime);
-
- // Argument 2 (x1): We need to load argument 2 (the previous index) into x1
- // before entering the exit frame.
- __ SmiUntag(x1, x10);
-
- // The fourth bit determines the string encoding in string_type.
- STATIC_ASSERT(kOneByteStringTag == 0x08);
- STATIC_ASSERT(kTwoByteStringTag == 0x00);
- STATIC_ASSERT(kStringEncodingMask == 0x08);
-
- // Find the code object based on the assumptions above.
- // kDataOneByteCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset
- // of kPointerSize to reach the latter.
- STATIC_ASSERT(JSRegExp::kDataOneByteCodeOffset + kPointerSize ==
- JSRegExp::kDataUC16CodeOffset);
- __ Mov(x10, kPointerSize);
- // We will need the encoding later: Latin1 = 0x08
- // UC16 = 0x00
- __ Ands(string_encoding, string_type, kStringEncodingMask);
- __ CzeroX(x10, ne);
- __ Add(x10, regexp_data, x10);
- __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataOneByteCodeOffset));
-
- // (E) Carry on. String handling is done.
-
- // 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(code_object, &runtime);
-
- // All checks done. Now push arguments for native regexp code.
- __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1,
- x10,
- x11);
-
// Isolates: note we add an additional parameter here (isolate pointer).
__ EnterExitFrame(false, x10, 1);
DCHECK(csp.Is(__ StackPointer()));
@@ -1501,50 +1287,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ Mov(x10, ExternalReference::isolate_address(isolate()));
__ Poke(x10, kPointerSize);
- Register length = w11;
- Register previous_index_in_bytes = w12;
- Register start = x13;
-
- // Load start of the subject string.
- __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag);
- // Load the length from the original subject string from the previous stack
- // frame. Therefore we have to use fp, which points exactly to two pointer
- // sizes below the previous sp. (Because creating a new stack frame pushes
- // the previous fp onto the stack and decrements sp by 2 * kPointerSize.)
- __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
- __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset));
-
- // Handle UC16 encoding, two bytes make one character.
- // string_encoding: if Latin1: 0x08
- // if UC16: 0x00
- STATIC_ASSERT(kStringEncodingMask == 0x08);
- __ Ubfx(string_encoding, string_encoding, 3, 1);
- __ Eor(string_encoding, string_encoding, 1);
- // string_encoding: if Latin1: 0
- // if UC16: 1
-
- // Convert string positions from characters to bytes.
- // Previous index is in x1.
- __ Lsl(previous_index_in_bytes, w1, string_encoding);
- __ Lsl(length, length, string_encoding);
- __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding);
-
// Argument 1 (x0): Subject string.
- __ Mov(x0, subject);
+ CHECK(x0.is(RegExpExecDescriptor::StringRegister()));
// Argument 2 (x1): Previous index, already there.
+ CHECK(x1.is(RegExpExecDescriptor::LastIndexRegister()));
- // Argument 3 (x2): Get the start of input.
- // Start of input = start of string + previous index + substring offset
- // (0 if the string
- // is not sliced).
- __ Add(w10, previous_index_in_bytes, sliced_string_offset);
- __ Add(x2, start, Operand(w10, UXTW));
-
- // Argument 4 (x3):
- // End of input = start of input + (length of input - previous index)
- __ Sub(w10, length, previous_index_in_bytes);
- __ Add(x3, x2, Operand(w10, UXTW));
+ // Argument 3 (x2): Input start.
+ // Argument 4 (x3): Input end.
+ CHECK(x2.is(RegExpExecDescriptor::StringStartRegister()));
+ CHECK(x3.is(RegExpExecDescriptor::StringEndRegister()));
// Argument 5 (x4): static offsets vector buffer.
__ Mov(x4, ExternalReference::address_of_static_offsets_vector(isolate()));
@@ -1555,6 +1307,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ Mov(x5, 0);
// Argument 7 (x6): 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(x10, address_of_regexp_stack_memory_address);
__ Ldr(x10, MemOperand(x10));
__ Mov(x11, address_of_regexp_stack_memory_size);
@@ -1565,184 +1321,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ Mov(x7, 1);
// Locate the code entry and call it.
+ Register code_object = RegExpExecDescriptor::CodeRegister();
__ Add(code_object, code_object, Code::kHeaderSize - kHeapObjectTag);
DirectCEntryStub stub(isolate());
stub.GenerateCall(masm, code_object);
__ LeaveExitFrame(false, x10, true);
- // The generated regexp code returns an int32 in w0.
- Label failure, exception;
- __ CompareAndBranch(w0, NativeRegExpMacroAssembler::FAILURE, eq, &failure);
- __ CompareAndBranch(w0,
- NativeRegExpMacroAssembler::EXCEPTION,
- eq,
- &exception);
- __ CompareAndBranch(w0, NativeRegExpMacroAssembler::RETRY, eq, &runtime);
-
- // Success: process the result from the native regexp code.
- Register number_of_capture_registers = x12;
-
- // Calculate number of capture registers (number_of_captures + 1) * 2
- // and store it in the last match info.
- __ Ldrsw(x10,
- UntagSmiFieldMemOperand(regexp_data,
- JSRegExp::kIrregexpCaptureCountOffset));
- __ Add(x10, x10, x10);
- __ Add(number_of_capture_registers, x10, 2);
-
- // Check that the last match info is a FixedArray.
- DCHECK(jssp.Is(__ StackPointer()));
- __ Peek(last_match_info_elements, kLastMatchInfoOffset);
- __ JumpIfSmi(last_match_info_elements, &runtime);
-
- // Check that the object has fast elements.
- __ Ldr(x10,
- FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
- __ JumpIfNotRoot(x10, Heap::kFixedArrayMapRootIndex, &runtime);
-
- // Check that the last match info has space for the capture registers and the
- // additional information (overhead).
- // (number_of_captures + 1) * 2 + overhead <= last match info size
- // (number_of_captures * 2) + 2 + overhead <= last match info size
- // number_of_capture_registers + overhead <= last match info size
- __ Ldrsw(x10,
- UntagSmiFieldMemOperand(last_match_info_elements,
- FixedArray::kLengthOffset));
- __ Add(x11, number_of_capture_registers, RegExpMatchInfo::kLastMatchOverhead);
- __ Cmp(x11, x10);
- __ B(gt, &runtime);
-
- // Store the capture count.
- __ SmiTag(x10, number_of_capture_registers);
- __ Str(x10, FieldMemOperand(last_match_info_elements,
- RegExpMatchInfo::kNumberOfCapturesOffset));
- // Store last subject and last input.
- __ Str(subject, FieldMemOperand(last_match_info_elements,
- RegExpMatchInfo::kLastSubjectOffset));
- // Use x10 as the subject string in order to only need
- // one RecordWriteStub.
- __ Mov(x10, subject);
- __ RecordWriteField(last_match_info_elements,
- RegExpMatchInfo::kLastSubjectOffset, x10, x11,
- kLRHasNotBeenSaved, kDontSaveFPRegs);
- __ Str(subject, FieldMemOperand(last_match_info_elements,
- RegExpMatchInfo::kLastInputOffset));
- __ Mov(x10, subject);
- __ RecordWriteField(last_match_info_elements,
- RegExpMatchInfo::kLastInputOffset, x10, x11,
- kLRHasNotBeenSaved, kDontSaveFPRegs);
-
- Register last_match_offsets = x13;
- Register offsets_vector_index = x14;
- Register current_offset = x15;
-
- // Get the static offsets vector filled by the native regexp code
- // and fill the last match info.
- ExternalReference address_of_static_offsets_vector =
- ExternalReference::address_of_static_offsets_vector(isolate());
- __ Mov(offsets_vector_index, address_of_static_offsets_vector);
-
- Label next_capture, done;
- // Capture register counter starts from number of capture registers and
- // iterates down to zero (inclusive).
- __ Add(last_match_offsets, last_match_info_elements,
- RegExpMatchInfo::kFirstCaptureOffset - kHeapObjectTag);
- __ Bind(&next_capture);
- __ Subs(number_of_capture_registers, number_of_capture_registers, 2);
- __ B(mi, &done);
- // Read two 32 bit values from the static offsets vector buffer into
- // an X register
- __ Ldr(current_offset,
- MemOperand(offsets_vector_index, kWRegSize * 2, PostIndex));
- // Store the smi values in the last match info.
- __ SmiTag(x10, current_offset);
- // Clearing the 32 bottom bits gives us a Smi.
- STATIC_ASSERT(kSmiTag == 0);
- __ Bic(x11, current_offset, kSmiShiftMask);
- __ Stp(x10,
- x11,
- MemOperand(last_match_offsets, kXRegSize * 2, PostIndex));
- __ B(&next_capture);
- __ Bind(&done);
-
- // Return last match info.
- __ Mov(x0, last_match_info_elements);
- // Drop the 4 arguments of the stub from the stack.
- __ Drop(4);
- __ Ret();
-
- __ Bind(&exception);
- Register exception_value = x0;
- // A stack overflow (on the backtrack stack) may have occured
- // in the RegExp code but no exception has been created yet.
- // If there is no pending exception, handle that in the runtime system.
- __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
- __ Mov(x11,
- Operand(ExternalReference(Isolate::kPendingExceptionAddress,
- isolate())));
- __ Ldr(exception_value, MemOperand(x11));
- __ Cmp(x10, exception_value);
- __ B(eq, &runtime);
-
- // For exception, throw the exception again.
- __ TailCallRuntime(Runtime::kRegExpExecReThrow);
-
- __ Bind(&failure);
- __ Mov(x0, Operand(isolate()->factory()->null_value()));
- // Drop the 4 arguments of the stub from the stack.
- __ Drop(4);
+ // Return the smi-tagged result.
+ __ SmiTag(x0);
__ Ret();
-
- __ Bind(&runtime);
- __ TailCallRuntime(Runtime::kRegExpExec);
-
- // Deferred code for string handling.
- // (5) Long external string? If not, go to (7).
- __ Bind(&not_seq_nor_cons);
- // Compare flags are still set.
- __ B(ne, &not_long_external); // Go to (7).
-
- // (6) External string. Make it, offset-wise, look like a sequential string.
- __ Bind(&external_string);
- if (masm->emit_debug_code()) {
- // Assert that we do not have a cons or slice (indirect strings) here.
- // Sequential strings have already been ruled out.
- __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
- __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset));
- __ Tst(x10, kIsIndirectStringMask);
- __ Check(eq, kExternalStringExpectedButNotFound);
- __ And(x10, x10, kStringRepresentationMask);
- __ Cmp(x10, 0);
- __ Check(ne, kExternalStringExpectedButNotFound);
- }
- __ Ldr(subject,
- FieldMemOperand(subject, ExternalString::kResourceDataOffset));
- // Move the pointer so that offset-wise, it looks like a sequential string.
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
- __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
- __ B(&seq_string); // Go to (4).
-
- // (7) If this is a short external string or not a string, bail out to
- // runtime.
- __ Bind(&not_long_external);
- STATIC_ASSERT(kShortExternalStringTag != 0);
- __ TestAndBranchIfAnySet(string_representation,
- kShortExternalStringMask | kIsNotStringMask,
- &runtime);
-
- // (8) Sliced or thin string. Replace subject with parent.
- Label thin_string;
- __ Cmp(string_representation, kThinStringTag);
- __ B(eq, &thin_string);
- __ Ldr(sliced_string_offset,
- UntagSmiFieldMemOperand(subject, SlicedString::kOffsetOffset));
- __ Ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
- __ B(&check_underlying); // Go to (1).
-
- __ bind(&thin_string);
- __ Ldr(subject, FieldMemOperand(subject, ThinString::kActualOffset));
- __ B(&check_underlying); // Go to (1).
#endif
}
« no previous file with comments | « src/arm/interface-descriptors-arm.cc ('k') | src/arm64/interface-descriptors-arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698