Index: src/mips64/code-stubs-mips64.cc |
diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc |
index 645599a03a1d96ae4854eacbe78900e5f1a090c2..1738ef432e9a2d344dd298253295aa45865b3521 100644 |
--- a/src/mips64/code-stubs-mips64.cc |
+++ b/src/mips64/code-stubs-mips64.cc |
@@ -1267,183 +1267,10 @@ void JSEntryStub::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. |
- // sp[0]: last_match_info (expected JSArray) |
- // sp[4]: previous index |
- // sp[8]: subject string |
- // sp[12]: JSRegExp object |
- |
- const int kLastMatchInfoOffset = 0 * kPointerSize; |
- const int kPreviousIndexOffset = 1 * kPointerSize; |
- const int kSubjectOffset = 2 * kPointerSize; |
- const int kJSRegExpOffset = 3 * kPointerSize; |
- |
- Label runtime; |
- // Allocation of registers for this function. 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. |
- // MIPS - using s0..s2, since we are not using CEntry Stub. |
- Register subject = s0; |
- Register regexp_data = s1; |
- Register last_match_info_elements = s2; |
- |
- // 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()); |
- __ li(a0, Operand(address_of_regexp_stack_memory_size)); |
- __ ld(a0, MemOperand(a0, 0)); |
- __ Branch(&runtime, eq, a0, Operand(zero_reg)); |
- |
- // Check that the first argument is a JSRegExp object. |
- __ ld(a0, MemOperand(sp, kJSRegExpOffset)); |
- STATIC_ASSERT(kSmiTag == 0); |
- __ JumpIfSmi(a0, &runtime); |
- __ GetObjectType(a0, a1, a1); |
- __ Branch(&runtime, ne, a1, Operand(JS_REGEXP_TYPE)); |
- |
- // Check that the RegExp has been compiled (data contains a fixed array). |
- __ ld(regexp_data, FieldMemOperand(a0, JSRegExp::kDataOffset)); |
- if (FLAG_debug_code) { |
- __ SmiTst(regexp_data, a4); |
- __ Check(nz, |
- kUnexpectedTypeForRegExpDataFixedArrayExpected, |
- a4, |
- Operand(zero_reg)); |
- __ GetObjectType(regexp_data, a0, a0); |
- __ Check(eq, |
- kUnexpectedTypeForRegExpDataFixedArrayExpected, |
- a0, |
- Operand(FIXED_ARRAY_TYPE)); |
- } |
- |
- // regexp_data: RegExp data (FixedArray) |
- // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
- __ ld(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
- __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); |
- |
- // regexp_data: RegExp data (FixedArray) |
- // Check that the number of captures fit in the static offsets vector buffer. |
- __ ld(a2, |
- FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
- // Check (number_of_captures + 1) * 2 <= offsets vector size |
- // Or number_of_captures * 2 <= offsets vector size - 2 |
- // Or number_of_captures <= offsets vector size / 2 - 1 |
- // Multiplying by 2 comes for free since a2 is smi-tagged. |
- STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
- int temp = Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1; |
- __ Branch(&runtime, hi, a2, Operand(Smi::FromInt(temp))); |
- |
- // Reset offset for possibly sliced string. |
- __ mov(t0, zero_reg); |
- __ ld(subject, MemOperand(sp, kSubjectOffset)); |
- __ JumpIfSmi(subject, &runtime); |
- __ mov(a3, subject); // Make a copy of the original subject string. |
- |
- // subject: subject string |
- // a3: subject string |
- // regexp_data: RegExp data (FixedArray) |
- // 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); |
- __ ld(a2, FieldMemOperand(subject, HeapObject::kMapOffset)); |
- __ lbu(a0, FieldMemOperand(a2, Map::kInstanceTypeOffset)); |
- |
- // (1) Sequential string? If yes, go to (4). |
- __ And(a1, |
- a0, |
- Operand(kIsNotStringMask | |
- kStringRepresentationMask | |
- kShortExternalStringMask)); |
- STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); |
- __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // 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); |
- // Go to (5). |
- __ Branch(¬_seq_nor_cons, ge, a1, Operand(kExternalStringTag)); |
- |
- // (3) Cons string. Check that it's flat. |
- // Replace subject with first string and reload instance type. |
- __ ld(a0, FieldMemOperand(subject, ConsString::kSecondOffset)); |
- __ LoadRoot(a1, Heap::kempty_stringRootIndex); |
- __ Branch(&runtime, ne, a0, Operand(a1)); |
- __ ld(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
- __ jmp(&check_underlying); |
- |
- // (4) Sequential string. Load regexp code according to encoding. |
- __ bind(&seq_string); |
- // subject: sequential subject string (or look-alike, external string) |
- // a3: original subject string |
- // Load previous index and check range before a3 is overwritten. We have to |
- // use a3 instead of subject here because subject might have been only made |
- // to look like a sequential string when it actually is an external string. |
- __ ld(a1, MemOperand(sp, kPreviousIndexOffset)); |
- __ JumpIfNotSmi(a1, &runtime); |
- __ ld(a3, FieldMemOperand(a3, String::kLengthOffset)); |
- __ Branch(&runtime, ls, a3, Operand(a1)); |
- __ SmiUntag(a1); |
- |
- STATIC_ASSERT(kStringEncodingMask == 8); |
- STATIC_ASSERT(kOneByteStringTag == 8); |
- STATIC_ASSERT(kTwoByteStringTag == 0); |
- __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for one_byte. |
- __ ld(t9, FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset)); |
- __ dsra(a3, a0, 3); // a3 is 1 for one_byte, 0 for UC16 (used below). |
- __ ld(a5, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); |
- __ Movz(t9, a5, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. |
- |
- // (E) Carry on. String handling is done. |
- // t9: 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(t9, &runtime); |
- |
- // a1: previous index |
- // a3: encoding of subject string (1 if one_byte, 0 if two_byte); |
- // t9: code |
- // subject: Subject string |
- // regexp_data: RegExp data (FixedArray) |
- // All checks done. Now push arguments for native regexp code. |
- __ IncrementCounter(isolate()->counters()->regexp_entry_native(), |
- 1, a0, a2); |
- |
// Isolates: note we add an additional parameter here (isolate pointer). |
const int kRegExpExecuteArguments = 9; |
const int kParameterRegisters = 8; |
@@ -1468,18 +1295,22 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { |
// [sp + 0] - saved ra |
// Argument 9: Pass current isolate address. |
- __ li(a0, Operand(ExternalReference::isolate_address(isolate()))); |
- __ sd(a0, MemOperand(sp, 1 * kPointerSize)); |
+ __ li(t1, Operand(ExternalReference::isolate_address(isolate()))); |
+ __ sd(t1, MemOperand(sp, 1 * kPointerSize)); |
// Argument 8: Indicate that this is a direct call from JavaScript. |
__ li(a7, Operand(1)); |
// Argument 7: Start (high end) of backtracking stack memory area. |
- __ li(a0, Operand(address_of_regexp_stack_memory_address)); |
- __ ld(a0, MemOperand(a0, 0)); |
- __ li(a2, Operand(address_of_regexp_stack_memory_size)); |
- __ ld(a2, MemOperand(a2, 0)); |
- __ daddu(a6, a0, a2); |
+ 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()); |
+ __ li(t1, Operand(address_of_regexp_stack_memory_address)); |
+ __ ld(t1, MemOperand(t1, 0)); |
+ __ li(t2, Operand(address_of_regexp_stack_memory_size)); |
+ __ ld(t2, MemOperand(t2, 0)); |
+ __ daddu(a6, t1, t2); |
// 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. |
@@ -1490,198 +1321,28 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { |
a4, |
Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); |
- // For arguments 4 and 3 get string length, calculate start of string data |
- // and calculate the shift of the index (0 for one_byte and 1 for two byte). |
- __ Daddu(t2, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); |
- __ Xor(a3, a3, Operand(1)); // 1 for 2-byte str, 0 for 1-byte. |
- // 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 moves up sp by 2 * kPointerSize.) |
- __ ld(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
- // If slice offset is not 0, load the length from the original sliced string. |
// Argument 4, a3: End of string data |
// Argument 3, a2: Start of string data |
- // Prepare start and end index of the input. |
- __ dsllv(t1, t0, a3); |
- __ daddu(t0, t2, t1); |
- __ dsllv(t1, a1, a3); |
- __ daddu(a2, t0, t1); |
+ CHECK(a3.is(RegExpExecDescriptor::StringEndRegister())); |
+ CHECK(a2.is(RegExpExecDescriptor::StringStartRegister())); |
- __ ld(t2, FieldMemOperand(subject, String::kLengthOffset)); |
- |
- __ SmiUntag(t2); |
- __ dsllv(t1, t2, a3); |
- __ daddu(a3, t0, t1); |
// Argument 2 (a1): Previous index. |
- // Already there |
+ CHECK(a1.is(RegExpExecDescriptor::LastIndexRegister())); |
// Argument 1 (a0): Subject string. |
- __ mov(a0, subject); |
+ CHECK(a0.is(RegExpExecDescriptor::StringRegister())); |
// Locate the code entry and call it. |
- __ Daddu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ Register code_reg = RegExpExecDescriptor::CodeRegister(); |
+ __ Daddu(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
DirectCEntryStub stub(isolate()); |
- stub.GenerateCall(masm, t9); |
+ stub.GenerateCall(masm, code_reg); |
__ LeaveExitFrame(false, no_reg, true); |
- // v0: result |
- // subject: subject string (callee saved) |
- // regexp_data: RegExp data (callee saved) |
- // last_match_info_elements: Last match info elements (callee saved) |
- // Check the result. |
- Label success; |
- __ Branch(&success, eq, v0, Operand(1)); |
- // We expect exactly one result since we force the called regexp to behave |
- // as non-global. |
- Label failure; |
- __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE)); |
- // If not exception it can only be retry. Handle that in the runtime system. |
- __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::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. |
- __ li(a1, Operand(isolate()->factory()->the_hole_value())); |
- __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
- isolate()))); |
- __ ld(v0, MemOperand(a2, 0)); |
- __ Branch(&runtime, eq, v0, Operand(a1)); |
- |
- // For exception, throw the exception again. |
- __ TailCallRuntime(Runtime::kRegExpExecReThrow); |
- |
- __ bind(&failure); |
- // For failure and exception return null. |
- __ li(v0, Operand(isolate()->factory()->null_value())); |
- __ DropAndRet(4); |
- |
- // Process the result from the native regexp code. |
- __ bind(&success); |
- |
- __ lw(a1, UntagSmiFieldMemOperand( |
- regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
- // Calculate number of capture registers (number_of_captures + 1) * 2. |
- __ Daddu(a1, a1, Operand(1)); |
- __ dsll(a1, a1, 1); // Multiply by 2. |
- |
- // Check that the last match info is a FixedArray. |
- __ ld(last_match_info_elements, MemOperand(sp, kLastMatchInfoOffset)); |
- __ JumpIfSmi(last_match_info_elements, &runtime); |
- // Check that the object has fast elements. |
- __ ld(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); |
- __ LoadRoot(at, Heap::kFixedArrayMapRootIndex); |
- __ Branch(&runtime, ne, a0, Operand(at)); |
- // Check that the last match info has space for the capture registers and the |
- // additional information. |
- __ ld(a0, |
- FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); |
- __ Daddu(a2, a1, Operand(RegExpMatchInfo::kLastMatchOverhead)); |
- |
- __ SmiUntag(at, a0); |
- __ Branch(&runtime, gt, a2, Operand(at)); |
- |
- // a1: number of capture registers |
- // subject: subject string |
- // Store the capture count. |
- __ SmiTag(a2, a1); // To smi. |
- __ sd(a2, FieldMemOperand(last_match_info_elements, |
- RegExpMatchInfo::kNumberOfCapturesOffset)); |
- // Store last subject and last input. |
- __ sd(subject, FieldMemOperand(last_match_info_elements, |
- RegExpMatchInfo::kLastSubjectOffset)); |
- __ mov(a2, subject); |
- __ RecordWriteField(last_match_info_elements, |
- RegExpMatchInfo::kLastSubjectOffset, subject, a7, |
- kRAHasNotBeenSaved, kDontSaveFPRegs); |
- __ mov(subject, a2); |
- __ sd(subject, FieldMemOperand(last_match_info_elements, |
- RegExpMatchInfo::kLastInputOffset)); |
- __ RecordWriteField(last_match_info_elements, |
- RegExpMatchInfo::kLastInputOffset, subject, a7, |
- kRAHasNotBeenSaved, 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()); |
- __ li(a2, Operand(address_of_static_offsets_vector)); |
- |
- // a1: number of capture registers |
- // a2: offsets vector |
- Label next_capture, done; |
- // Capture register counter starts from number of capture registers and |
- // counts down until wrapping after zero. |
- __ Daddu(a0, last_match_info_elements, |
- Operand(RegExpMatchInfo::kFirstCaptureOffset - kHeapObjectTag)); |
- __ bind(&next_capture); |
- __ Dsubu(a1, a1, Operand(1)); |
- __ Branch(&done, lt, a1, Operand(zero_reg)); |
- // Read the value from the static offsets vector buffer. |
- __ lw(a3, MemOperand(a2, 0)); |
- __ daddiu(a2, a2, kIntSize); |
- // Store the smi value in the last match info. |
- __ SmiTag(a3); |
- __ sd(a3, MemOperand(a0, 0)); |
- __ Branch(&next_capture, USE_DELAY_SLOT); |
- __ daddiu(a0, a0, kPointerSize); // In branch delay slot. |
- |
- __ bind(&done); |
- |
- // Return last match info. |
- __ mov(v0, last_match_info_elements); |
- __ DropAndRet(4); |
- |
- // Do the runtime call to execute the regexp. |
- __ bind(&runtime); |
- __ TailCallRuntime(Runtime::kRegExpExec); |
- |
- // Deferred code for string handling. |
- // (5) Long external string? If not, go to (7). |
- __ bind(¬_seq_nor_cons); |
- // Go to (7). |
- __ Branch(¬_long_external, gt, a1, Operand(kExternalStringTag)); |
- |
- // (6) External string. Make it, offset-wise, look like a sequential string. |
- __ bind(&external_string); |
- __ ld(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
- __ lbu(a0, FieldMemOperand(a0, 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. |
- __ And(at, a0, Operand(kIsIndirectStringMask)); |
- __ Assert(eq, |
- kExternalStringExpectedButNotFound, |
- at, |
- Operand(zero_reg)); |
- } |
- __ ld(subject, |
- FieldMemOperand(subject, ExternalString::kResourceDataOffset)); |
- // Move the pointer so that offset-wise, it looks like a sequential string. |
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
- __ Dsubu(subject, |
- subject, |
- SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
- __ jmp(&seq_string); // Go to (4). |
- |
- // (7) Short external string or not a string? If yes, bail out to runtime. |
- __ bind(¬_long_external); |
- STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); |
- __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask)); |
- __ Branch(&runtime, ne, at, Operand(zero_reg)); |
- |
- // (8) Sliced or thin string. Replace subject with parent. Go to (4). |
- Label thin_string; |
- __ Branch(&thin_string, eq, a1, Operand(kThinStringTag)); |
- // Load offset into t0 and replace subject string with parent. |
- __ ld(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); |
- __ SmiUntag(t0); |
- __ ld(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); |
- __ jmp(&check_underlying); // Go to (1). |
- |
- __ bind(&thin_string); |
- __ ld(subject, FieldMemOperand(subject, ThinString::kActualOffset)); |
- __ jmp(&check_underlying); // Go to (1). |
+ // Return the smi-tagged result. |
+ __ SmiTag(v0); |
+ __ Ret(); |
#endif // V8_INTERPRETED_REGEXP |
} |