| Index: src/arm64/code-stubs-arm64.cc
|
| diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
|
| index 082565f20c2e40f8de5430906450c310b755ceb1..923f8e0e04d4ee58783f88823584a26a4306a886 100644
|
| --- a/src/arm64/code-stubs-arm64.cc
|
| +++ b/src/arm64/code-stubs-arm64.cc
|
| @@ -1264,223 +1264,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()));
|
| @@ -1496,50 +1282,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()));
|
| @@ -1550,6 +1302,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);
|
| @@ -1560,184 +1316,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
|
| }
|
|
|
|
|