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, ¬_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(¬_seq_nor_cons); |
- // Compare flags are still set. |
- __ B(ne, ¬_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(¬_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 |
} |