| Index: src/mips/code-stubs-mips.cc
|
| diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
|
| index c7010c9c23c08564deafaa633f361c9cfd254048..2953821cb96dcff1812040f061f0fa892085e807 100644
|
| --- a/src/mips/code-stubs-mips.cc
|
| +++ b/src/mips/code-stubs-mips.cc
|
| @@ -351,7 +351,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
|
| }
|
|
|
|
|
| -void NewStringAddStub::InitializeInterfaceDescriptor(
|
| +void StringAddStub::InitializeInterfaceDescriptor(
|
| Isolate* isolate,
|
| CodeStubInterfaceDescriptor* descriptor) {
|
| static Register registers[] = { a1, a0 };
|
| @@ -4561,355 +4561,6 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| -void StringAddStub::Generate(MacroAssembler* masm) {
|
| - Label call_runtime, call_builtin;
|
| - Builtins::JavaScript builtin_id = Builtins::ADD;
|
| -
|
| - Counters* counters = masm->isolate()->counters();
|
| -
|
| - // Stack on entry:
|
| - // sp[0]: second argument (right).
|
| - // sp[4]: first argument (left).
|
| -
|
| - // Load the two arguments.
|
| - __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument.
|
| - __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
|
| -
|
| - // Make sure that both arguments are strings if not known in advance.
|
| - // Otherwise, at least one of the arguments is definitely a string,
|
| - // and we convert the one that is not known to be a string.
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
|
| - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
|
| - __ JumpIfEitherSmi(a0, a1, &call_runtime);
|
| - // Load instance types.
|
| - __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
|
| - __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
|
| - __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
| - __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
| - STATIC_ASSERT(kStringTag == 0);
|
| - // If either is not a string, go to runtime.
|
| - __ Or(t4, t0, Operand(t1));
|
| - __ And(t4, t4, Operand(kIsNotStringMask));
|
| - __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
|
| - } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
|
| - GenerateConvertArgument(
|
| - masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin);
|
| - builtin_id = Builtins::STRING_ADD_RIGHT;
|
| - } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
|
| - GenerateConvertArgument(
|
| - masm, 0 * kPointerSize, a1, a2, a3, t0, t1, &call_builtin);
|
| - builtin_id = Builtins::STRING_ADD_LEFT;
|
| - }
|
| -
|
| - // Both arguments are strings.
|
| - // a0: first string
|
| - // a1: second string
|
| - // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - {
|
| - Label strings_not_empty;
|
| - // Check if either of the strings are empty. In that case return the other.
|
| - // These tests use zero-length check on string-length whch is an Smi.
|
| - // Assert that Smi::FromInt(0) is really 0.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - ASSERT(Smi::FromInt(0) == 0);
|
| - __ lw(a2, FieldMemOperand(a0, String::kLengthOffset));
|
| - __ lw(a3, FieldMemOperand(a1, String::kLengthOffset));
|
| - __ mov(v0, a0); // Assume we'll return first string (from a0).
|
| - __ Movz(v0, a1, a2); // If first is empty, return second (from a1).
|
| - __ slt(t4, zero_reg, a2); // if (a2 > 0) t4 = 1.
|
| - __ slt(t5, zero_reg, a3); // if (a3 > 0) t5 = 1.
|
| - __ and_(t4, t4, t5); // Branch if both strings were non-empty.
|
| - __ Branch(&strings_not_empty, ne, t4, Operand(zero_reg));
|
| -
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - __ bind(&strings_not_empty);
|
| - }
|
| -
|
| - // Untag both string-lengths.
|
| - __ sra(a2, a2, kSmiTagSize);
|
| - __ sra(a3, a3, kSmiTagSize);
|
| -
|
| - // Both strings are non-empty.
|
| - // a0: first string
|
| - // a1: second string
|
| - // a2: length of first string
|
| - // a3: length of second string
|
| - // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // Look at the length of the result of adding the two strings.
|
| - Label string_add_flat_result, longer_than_two;
|
| - // Adding two lengths can't overflow.
|
| - STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
|
| - __ Addu(t2, a2, Operand(a3));
|
| - // Use the string table when adding two one character strings, as it
|
| - // helps later optimizations to return a string here.
|
| - __ Branch(&longer_than_two, ne, t2, Operand(2));
|
| -
|
| - // Check that both strings are non-external ASCII strings.
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
|
| - __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
|
| - __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
|
| - __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
| - __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
| - }
|
| - __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3,
|
| - &call_runtime);
|
| -
|
| - // Get the two characters forming the sub string.
|
| - __ lbu(a2, FieldMemOperand(a0, SeqOneByteString::kHeaderSize));
|
| - __ lbu(a3, FieldMemOperand(a1, SeqOneByteString::kHeaderSize));
|
| -
|
| - // Try to lookup two character string in string table. If it is not found
|
| - // just allocate a new one.
|
| - Label make_two_character_string;
|
| - StringHelper::GenerateTwoCharacterStringTableProbe(
|
| - masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string);
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - __ bind(&make_two_character_string);
|
| - // Resulting string has length 2 and first chars of two strings
|
| - // are combined into single halfword in a2 register.
|
| - // So we can fill resulting string without two loops by a single
|
| - // halfword store instruction (which assumes that processor is
|
| - // in a little endian mode).
|
| - __ li(t2, Operand(2));
|
| - __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
|
| - __ sh(a2, FieldMemOperand(v0, SeqOneByteString::kHeaderSize));
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - __ bind(&longer_than_two);
|
| - // Check if resulting string will be flat.
|
| - __ Branch(&string_add_flat_result, lt, t2, Operand(ConsString::kMinLength));
|
| - // Handle exceptionally long strings in the runtime system.
|
| - STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
|
| - ASSERT(IsPowerOf2(String::kMaxLength + 1));
|
| - // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
|
| - __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1));
|
| -
|
| - // If result is not supposed to be flat, allocate a cons string object.
|
| - // If both strings are ASCII the result is an ASCII cons string.
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
|
| - __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
|
| - __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
|
| - __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
| - __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
| - }
|
| - Label non_ascii, allocated, ascii_data;
|
| - STATIC_ASSERT(kTwoByteStringTag == 0);
|
| - // Branch to non_ascii if either string-encoding field is zero (non-ASCII).
|
| - __ And(t4, t0, Operand(t1));
|
| - __ And(t4, t4, Operand(kStringEncodingMask));
|
| - __ Branch(&non_ascii, eq, t4, Operand(zero_reg));
|
| -
|
| - // Allocate an ASCII cons string.
|
| - __ bind(&ascii_data);
|
| - __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime);
|
| - __ bind(&allocated);
|
| - // Fill the fields of the cons string.
|
| - Label skip_write_barrier, after_writing;
|
| - ExternalReference high_promotion_mode = ExternalReference::
|
| - new_space_high_promotion_mode_active_address(masm->isolate());
|
| - __ li(t0, Operand(high_promotion_mode));
|
| - __ lw(t0, MemOperand(t0, 0));
|
| - __ Branch(&skip_write_barrier, eq, t0, Operand(zero_reg));
|
| -
|
| - __ mov(t3, v0);
|
| - __ sw(a0, FieldMemOperand(t3, ConsString::kFirstOffset));
|
| - __ RecordWriteField(t3,
|
| - ConsString::kFirstOffset,
|
| - a0,
|
| - t0,
|
| - kRAHasNotBeenSaved,
|
| - kDontSaveFPRegs);
|
| - __ sw(a1, FieldMemOperand(t3, ConsString::kSecondOffset));
|
| - __ RecordWriteField(t3,
|
| - ConsString::kSecondOffset,
|
| - a1,
|
| - t0,
|
| - kRAHasNotBeenSaved,
|
| - kDontSaveFPRegs);
|
| - __ jmp(&after_writing);
|
| -
|
| - __ bind(&skip_write_barrier);
|
| - __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset));
|
| - __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset));
|
| -
|
| - __ bind(&after_writing);
|
| -
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - __ bind(&non_ascii);
|
| - // At least one of the strings is two-byte. Check whether it happens
|
| - // to contain only one byte characters.
|
| - // t0: first instance type.
|
| - // t1: second instance type.
|
| - // Branch to if _both_ instances have kOneByteDataHintMask set.
|
| - __ And(at, t0, Operand(kOneByteDataHintMask));
|
| - __ and_(at, at, t1);
|
| - __ Branch(&ascii_data, ne, at, Operand(zero_reg));
|
| - __ Xor(t0, t0, Operand(t1));
|
| - STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
|
| - __ And(t0, t0, Operand(kOneByteStringTag | kOneByteDataHintTag));
|
| - __ Branch(&ascii_data, eq, t0,
|
| - Operand(kOneByteStringTag | kOneByteDataHintTag));
|
| -
|
| - // Allocate a two byte cons string.
|
| - __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime);
|
| - __ Branch(&allocated);
|
| -
|
| - // We cannot encounter sliced strings or cons strings here since:
|
| - STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
|
| - // Handle creating a flat result from either external or sequential strings.
|
| - // Locate the first characters' locations.
|
| - // a0: first string
|
| - // a1: second string
|
| - // a2: length of first string
|
| - // a3: length of second string
|
| - // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // t2: sum of lengths.
|
| - Label first_prepared, second_prepared;
|
| - __ bind(&string_add_flat_result);
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
|
| - __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
|
| - __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
|
| - __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
| - __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
| - }
|
| - // Check whether both strings have same encoding
|
| - __ Xor(t3, t0, Operand(t1));
|
| - __ And(t3, t3, Operand(kStringEncodingMask));
|
| - __ Branch(&call_runtime, ne, t3, Operand(zero_reg));
|
| -
|
| - STATIC_ASSERT(kSeqStringTag == 0);
|
| - __ And(t4, t0, Operand(kStringRepresentationMask));
|
| -
|
| - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| - Label skip_first_add;
|
| - __ Branch(&skip_first_add, ne, t4, Operand(zero_reg));
|
| - __ Branch(USE_DELAY_SLOT, &first_prepared);
|
| - __ addiu(t3, a0, SeqOneByteString::kHeaderSize - kHeapObjectTag);
|
| - __ bind(&skip_first_add);
|
| - // External string: rule out short external string and load string resource.
|
| - STATIC_ASSERT(kShortExternalStringTag != 0);
|
| - __ And(t4, t0, Operand(kShortExternalStringMask));
|
| - __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
|
| - __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset));
|
| - __ bind(&first_prepared);
|
| -
|
| - STATIC_ASSERT(kSeqStringTag == 0);
|
| - __ And(t4, t1, Operand(kStringRepresentationMask));
|
| - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| - Label skip_second_add;
|
| - __ Branch(&skip_second_add, ne, t4, Operand(zero_reg));
|
| - __ Branch(USE_DELAY_SLOT, &second_prepared);
|
| - __ addiu(a1, a1, SeqOneByteString::kHeaderSize - kHeapObjectTag);
|
| - __ bind(&skip_second_add);
|
| - // External string: rule out short external string and load string resource.
|
| - STATIC_ASSERT(kShortExternalStringTag != 0);
|
| - __ And(t4, t1, Operand(kShortExternalStringMask));
|
| - __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
|
| - __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset));
|
| - __ bind(&second_prepared);
|
| -
|
| - Label non_ascii_string_add_flat_result;
|
| - // t3: first character of first string
|
| - // a1: first character of second string
|
| - // a2: length of first string
|
| - // a3: length of second string
|
| - // t2: sum of lengths.
|
| - // Both strings have the same encoding.
|
| - STATIC_ASSERT(kTwoByteStringTag == 0);
|
| - __ And(t4, t1, Operand(kStringEncodingMask));
|
| - __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg));
|
| -
|
| - __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
|
| - __ Addu(t2, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
|
| - // v0: result string.
|
| - // t3: first character of first string.
|
| - // a1: first character of second string
|
| - // a2: length of first string.
|
| - // a3: length of second string.
|
| - // t2: first character of result.
|
| -
|
| - StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true);
|
| - // t2: next character of result.
|
| - StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true);
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - __ bind(&non_ascii_string_add_flat_result);
|
| - __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime);
|
| - __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
|
| - // v0: result string.
|
| - // t3: first character of first string.
|
| - // a1: first character of second string.
|
| - // a2: length of first string.
|
| - // a3: length of second string.
|
| - // t2: first character of result.
|
| - StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false);
|
| - // t2: next character of result.
|
| - StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false);
|
| -
|
| - __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
|
| - __ DropAndRet(2);
|
| -
|
| - // Just jump to runtime to add the two strings.
|
| - __ bind(&call_runtime);
|
| - __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
|
| -
|
| - if (call_builtin.is_linked()) {
|
| - __ bind(&call_builtin);
|
| - __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
|
| - }
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
|
| - __ push(a0);
|
| - __ push(a1);
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
|
| - __ pop(a1);
|
| - __ pop(a0);
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
|
| - int stack_offset,
|
| - Register arg,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - Register scratch4,
|
| - Label* slow) {
|
| - // First check if the argument is already a string.
|
| - Label not_string, done;
|
| - __ JumpIfSmi(arg, ¬_string);
|
| - __ GetObjectType(arg, scratch1, scratch1);
|
| - __ Branch(&done, lt, scratch1, Operand(FIRST_NONSTRING_TYPE));
|
| -
|
| - // Check the number to string cache.
|
| - __ bind(¬_string);
|
| - // Puts the cached result into scratch1.
|
| - __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow);
|
| - __ mov(arg, scratch1);
|
| - __ sw(arg, MemOperand(sp, stack_offset));
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
|
| ASSERT(state_ == CompareIC::SMI);
|
| Label miss;
|
|
|