From e5f1ac1deddfca823f94a70b0362154ff05b8620 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Wed, 22 Jan 2014 13:48:05 +0000 Subject: [PATCH] Get rid of the unused native code StringAddStub. BUG=v8:2990 LOG=n R=hpayer@chromium.org Review URL: https://codereview.chromium.org/144023009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18752 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 525 +-------------------------------------- src/arm/code-stubs-arm.h | 55 ---- src/arm/full-codegen-arm.cc | 19 +- src/arm/lithium-arm.cc | 8 +- src/arm/lithium-codegen-arm.cc | 17 +- src/code-stubs-hydrogen.cc | 10 +- src/code-stubs.cc | 8 +- src/code-stubs.h | 35 ++- src/flag-definitions.h | 2 - src/ia32/code-stubs-ia32.cc | 514 +------------------------------------- src/ia32/code-stubs-ia32.h | 53 ---- src/ia32/full-codegen-ia32.cc | 19 +- src/ia32/lithium-codegen-ia32.cc | 17 +- src/ia32/lithium-ia32.cc | 8 +- src/isolate.cc | 2 +- src/mips/code-stubs-mips.cc | 517 +------------------------------------- src/mips/code-stubs-mips.h | 55 ---- src/mips/full-codegen-mips.cc | 20 +- src/mips/lithium-codegen-mips.cc | 17 +- src/mips/lithium-mips.cc | 8 +- src/x64/code-stubs-x64.cc | 488 +----------------------------------- src/x64/code-stubs-x64.h | 48 ---- src/x64/full-codegen-x64.cc | 19 +- src/x64/lithium-codegen-x64.cc | 17 +- src/x64/lithium-x64.cc | 8 +- 25 files changed, 79 insertions(+), 2410 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 758d35f..5cc02e4 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -350,7 +350,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( } -void NewStringAddStub::InitializeInterfaceDescriptor( +void StringAddStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { static Register registers[] = { r1, r0 }; @@ -3468,36 +3468,6 @@ void StringCharFromCodeGenerator::GenerateSlow( } -void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii) { - Label loop; - Label done; - // This loop just copies one character at a time, as it is only used for very - // short strings. - if (!ascii) { - __ add(count, count, Operand(count), SetCC); - } else { - __ cmp(count, Operand::Zero()); - } - __ b(eq, &done); - - __ bind(&loop); - __ ldrb(scratch, MemOperand(src, 1, PostIndex)); - // Perform sub between load and dependent store to get the load time to - // complete. - __ sub(count, count, Operand(1), SetCC); - __ strb(scratch, MemOperand(dest, 1, PostIndex)); - // last iteration. - __ b(gt, &loop); - - __ bind(&done); -} - - enum CopyCharactersFlags { COPY_ASCII = 1, DEST_ALWAYS_ALIGNED = 2 @@ -3645,143 +3615,6 @@ void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, } -void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found) { - // Register scratch3 is the general scratch register in this function. - Register scratch = scratch3; - - // Make sure that both characters are not digits as such strings has a - // different hash algorithm. Don't try to look for these in the string table. - Label not_array_index; - __ sub(scratch, c1, Operand(static_cast('0'))); - __ cmp(scratch, Operand(static_cast('9' - '0'))); - __ b(hi, ¬_array_index); - __ sub(scratch, c2, Operand(static_cast('0'))); - __ cmp(scratch, Operand(static_cast('9' - '0'))); - - // If check failed combine both characters into single halfword. - // This is required by the contract of the method: code at the - // not_found branch expects this combination in c1 register - __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); - __ b(ls, not_found); - - __ bind(¬_array_index); - // Calculate the two character string hash. - Register hash = scratch1; - StringHelper::GenerateHashInit(masm, hash, c1); - StringHelper::GenerateHashAddCharacter(masm, hash, c2); - StringHelper::GenerateHashGetHash(masm, hash); - - // Collect the two characters in a register. - Register chars = c1; - __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); - - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string. - - // Load string table - // Load address of first element of the string table. - Register string_table = c2; - __ LoadRoot(string_table, Heap::kStringTableRootIndex); - - Register undefined = scratch4; - __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); - - // Calculate capacity mask from the string table capacity. - Register mask = scratch2; - __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset)); - __ mov(mask, Operand(mask, ASR, 1)); - __ sub(mask, mask, Operand(1)); - - // Calculate untagged address of the first element of the string table. - Register first_string_table_element = string_table; - __ add(first_string_table_element, string_table, - Operand(StringTable::kElementsStartOffset - kHeapObjectTag)); - - // Registers - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string - // mask: capacity mask - // first_string_table_element: address of the first element of - // the string table - // undefined: the undefined object - // scratch: - - - // Perform a number of probes in the string table. - const int kProbes = 4; - Label found_in_string_table; - Label next_probe[kProbes]; - Register candidate = scratch5; // Scratch register contains candidate. - for (int i = 0; i < kProbes; i++) { - // Calculate entry in string table. - if (i > 0) { - __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i))); - } else { - __ mov(candidate, hash); - } - - __ and_(candidate, candidate, Operand(mask)); - - // Load the entry from the symble table. - STATIC_ASSERT(StringTable::kEntrySize == 1); - __ ldr(candidate, - MemOperand(first_string_table_element, - candidate, - LSL, - kPointerSizeLog2)); - - // If entry is undefined no string with this hash can be found. - Label is_string; - __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE); - __ b(ne, &is_string); - - __ cmp(undefined, candidate); - __ b(eq, not_found); - // Must be the hole (deleted entry). - if (FLAG_debug_code) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(ip, candidate); - __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole); - } - __ jmp(&next_probe[i]); - - __ bind(&is_string); - - // Check that the candidate is a non-external ASCII string. The instance - // type is still in the scratch register from the CompareObjectType - // operation. - __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]); - - // If length is not 2 the string is not a candidate. - __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset)); - __ cmp(scratch, Operand(Smi::FromInt(2))); - __ b(ne, &next_probe[i]); - - // Check if the two characters match. - // Assumes that word load is little endian. - __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); - __ cmp(chars, scratch); - __ b(eq, &found_in_string_table); - __ bind(&next_probe[i]); - } - - // No matching 2 character string found by probing. - __ jmp(not_found); - - // Scratch register contains result when we fall through to here. - Register result = candidate; - __ bind(&found_in_string_table); - __ Move(r0, result); -} - - void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character) { @@ -4433,362 +4266,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. - __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. - __ ldr(r1, 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(r0, r1, &call_runtime); - // Load instance types. - __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); - STATIC_ASSERT(kStringTag == 0); - // If either is not a string, go to runtime. - __ tst(r4, Operand(kIsNotStringMask)); - __ tst(r5, Operand(kIsNotStringMask), eq); - __ b(ne, &call_runtime); - } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); - GenerateConvertArgument( - masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &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, r1, r2, r3, r4, r5, &call_builtin); - builtin_id = Builtins::STRING_ADD_LEFT; - } - - // Both arguments are strings. - // r0: first string - // r1: second string - // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) - // r5: 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. - __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset)); - __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); - STATIC_ASSERT(kSmiTag == 0); - __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty. - __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second. - STATIC_ASSERT(kSmiTag == 0); - // Else test if second string is empty. - __ cmp(r3, Operand(Smi::FromInt(0)), ne); - __ b(ne, &strings_not_empty); // If either string was empty, return r0. - - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - __ bind(&strings_not_empty); - } - - __ SmiUntag(r2); - __ SmiUntag(r3); - // Both strings are non-empty. - // r0: first string - // r1: second string - // r2: length of first string - // r3: length of second string - // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) - // r5: 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); - __ add(r6, r2, Operand(r3)); - // Use the string table when adding two one character strings, as it - // helps later optimizations to return a string here. - __ cmp(r6, Operand(2)); - __ b(ne, &longer_than_two); - - // Check that both strings are non-external ASCII strings. - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { - __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); - } - __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r3, - &call_runtime); - - // Get the two characters forming the sub string. - __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); - __ ldrb(r3, FieldMemOperand(r1, 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, r2, r3, r6, r0, r4, r5, r9, &make_two_character_string); - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - __ bind(&make_two_character_string); - // Resulting string has length 2 and first chars of two strings - // are combined into single halfword in r2 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) - __ mov(r6, Operand(2)); - __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); - __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - __ bind(&longer_than_two); - // Check if resulting string will be flat. - __ cmp(r6, Operand(ConsString::kMinLength)); - __ b(lt, &string_add_flat_result); - // 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. - __ cmp(r6, Operand(String::kMaxLength + 1)); - __ b(hs, &call_runtime); - - // 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) { - __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); - } - Label non_ascii, allocated, ascii_data; - STATIC_ASSERT(kTwoByteStringTag == 0); - __ tst(r4, Operand(kStringEncodingMask)); - __ tst(r5, Operand(kStringEncodingMask), ne); - __ b(eq, &non_ascii); - - // Allocate an ASCII cons string. - __ bind(&ascii_data); - __ AllocateAsciiConsString(r3, r6, r4, r5, &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()); - __ mov(r4, Operand(high_promotion_mode)); - __ ldr(r4, MemOperand(r4, 0)); - __ cmp(r4, Operand::Zero()); - __ b(eq, &skip_write_barrier); - - __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset)); - __ RecordWriteField(r3, - ConsString::kFirstOffset, - r0, - r4, - kLRHasNotBeenSaved, - kDontSaveFPRegs); - __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset)); - __ RecordWriteField(r3, - ConsString::kSecondOffset, - r1, - r4, - kLRHasNotBeenSaved, - kDontSaveFPRegs); - __ jmp(&after_writing); - - __ bind(&skip_write_barrier); - __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset)); - __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset)); - - __ bind(&after_writing); - - __ mov(r0, Operand(r3)); - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - __ bind(&non_ascii); - // At least one of the strings is two-byte. Check whether it happens - // to contain only one byte characters. - // r4: first instance type. - // r5: second instance type. - __ tst(r4, Operand(kOneByteDataHintMask)); - __ tst(r5, Operand(kOneByteDataHintMask), ne); - __ b(ne, &ascii_data); - __ eor(r4, r4, Operand(r5)); - STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); - __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag)); - __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag)); - __ b(eq, &ascii_data); - - // Allocate a two byte cons string. - __ AllocateTwoByteConsString(r3, r6, r4, r5, &call_runtime); - __ jmp(&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. - // r0: first string - // r1: second string - // r2: length of first string - // r3: length of second string - // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) - // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) - // r6: sum of lengths. - Label first_prepared, second_prepared; - __ bind(&string_add_flat_result); - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { - __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); - } - - // Check whether both strings have same encoding - __ eor(ip, r4, Operand(r5)); - ASSERT(__ ImmediateFitsAddrMode1Instruction(kStringEncodingMask)); - __ tst(ip, Operand(kStringEncodingMask)); - __ b(ne, &call_runtime); - - STATIC_ASSERT(kSeqStringTag == 0); - __ tst(r4, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ add(r6, - r0, - Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), - LeaveCC, - eq); - __ b(eq, &first_prepared); - // External string: rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ tst(r4, Operand(kShortExternalStringMask)); - __ b(ne, &call_runtime); - __ ldr(r6, FieldMemOperand(r0, ExternalString::kResourceDataOffset)); - __ bind(&first_prepared); - - STATIC_ASSERT(kSeqStringTag == 0); - __ tst(r5, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ add(r1, - r1, - Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), - LeaveCC, - eq); - __ b(eq, &second_prepared); - // External string: rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ tst(r5, Operand(kShortExternalStringMask)); - __ b(ne, &call_runtime); - __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset)); - __ bind(&second_prepared); - - Label non_ascii_string_add_flat_result; - // r6: first character of first string - // r1: first character of second string - // r2: length of first string. - // r3: length of second string. - // Both strings have the same encoding. - STATIC_ASSERT(kTwoByteStringTag == 0); - __ tst(r5, Operand(kStringEncodingMask)); - __ b(eq, &non_ascii_string_add_flat_result); - - __ add(r2, r2, Operand(r3)); - __ AllocateAsciiString(r0, r2, r4, r5, r9, &call_runtime); - __ sub(r2, r2, Operand(r3)); - __ add(r5, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - // r0: result string. - // r6: first character of first string. - // r1: first character of second string. - // r2: length of first string. - // r3: length of second string. - // r5: first character of result. - StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, true); - // r5: next character of result. - StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, true); - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - __ bind(&non_ascii_string_add_flat_result); - __ add(r2, r2, Operand(r3)); - __ AllocateTwoByteString(r0, r2, r4, r5, r9, &call_runtime); - __ sub(r2, r2, Operand(r3)); - __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // r0: result string. - // r6: first character of first string. - // r1: first character of second string. - // r2: length of first string. - // r3: length of second string. - // r5: first character of result. - StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, false); - // r5: next character of result. - StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, false); - __ IncrementCounter(counters->string_add_native(), 1, r2, r3); - __ add(sp, sp, Operand(2 * kPointerSize)); - __ Ret(); - - // 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(r0); - __ push(r1); -} - - -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) { - __ pop(r1); - __ pop(r0); -} - - -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); - __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE); - __ b(lt, &done); - - // Check the number to string cache. - __ bind(¬_string); - // Puts the cached result into scratch1. - __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow); - __ mov(arg, scratch1); - __ str(arg, MemOperand(sp, stack_offset)); - __ bind(&done); -} - - void ICCompareStub::GenerateSmis(MacroAssembler* masm) { ASSERT(state_ == CompareIC::SMI); Label miss; diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index 9b21d6f..7a371f1 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h @@ -57,18 +57,6 @@ class StoreBufferOverflowStub: public PlatformCodeStub { class StringHelper : public AllStatic { public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersLong adds too much - // overhead. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); - // Generate code for copying a large number of characters. This function // is allowed to spend extra time setting up conditions to make copying // faster. Copying of overlapping regions is not supported. @@ -84,23 +72,6 @@ class StringHelper : public AllStatic { int flags); - // Probe the string table for a two character string. If the string is - // not found by probing a jump to the label not_found is performed. This jump - // does not guarantee that the string is not in the string table. If the - // string is found the code falls through with the string in register r0. - // Contents of both c1 and c2 registers are modified. At the exit c1 is - // guaranteed to contain halfword with low and high bytes equal to - // initial contents of c1 and c2 respectively. - static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found); - // Generate string hash. static void GenerateHashInit(MacroAssembler* masm, Register hash, @@ -118,32 +89,6 @@ class StringHelper : public AllStatic { }; -class StringAddStub: public PlatformCodeStub { - public: - explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} - - private: - Major MajorKey() { return StringAdd; } - int MinorKey() { return flags_; } - - void Generate(MacroAssembler* masm); - - void GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Label* slow); - - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateRegisterArgsPop(MacroAssembler* masm); - - const StringAddFlags flags_; -}; - - class SubStringStub: public PlatformCodeStub { public: SubStringStub() {} diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 224e0c7..32d7e60 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -3674,21 +3674,12 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { ZoneList* args = expr->arguments(); ASSERT_EQ(2, args->length()); + VisitForStackValue(args->at(0)); + VisitForAccumulatorValue(args->at(1)); - if (FLAG_new_string_add) { - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - - __ pop(r1); - NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); - __ CallStub(&stub); - } else { - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); - - StringAddStub stub(STRING_ADD_CHECK_BOTH); - __ CallStub(&stub); - } + __ pop(r1); + StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); + __ CallStub(&stub); context()->Plug(r0); } diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 3002ba9..8a91216 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2280,12 +2280,8 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { LOperand* context = UseFixed(instr->context(), cp); - LOperand* left = FLAG_new_string_add - ? UseFixed(instr->left(), r1) - : UseRegisterAtStart(instr->left()); - LOperand* right = FLAG_new_string_add - ? UseFixed(instr->right(), r0) - : UseRegisterAtStart(instr->right()); + LOperand* left = UseFixed(instr->left(), r1); + LOperand* right = UseFixed(instr->right(), r0); return MarkAsCall( DefineFixed(new(zone()) LStringAdd(context, left, right), r0), instr); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 3a59100..37d5cf9 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -4508,18 +4508,11 @@ void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { void LCodeGen::DoStringAdd(LStringAdd* instr) { ASSERT(ToRegister(instr->context()).is(cp)); - if (FLAG_new_string_add) { - ASSERT(ToRegister(instr->left()).is(r1)); - ASSERT(ToRegister(instr->right()).is(r0)); - NewStringAddStub stub(instr->hydrogen()->flags(), - isolate()->heap()->GetPretenureMode()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } else { - __ push(ToRegister(instr->left())); - __ push(ToRegister(instr->right())); - StringAddStub stub(instr->hydrogen()->flags()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } + ASSERT(ToRegister(instr->left()).is(r1)); + ASSERT(ToRegister(instr->right()).is(r0)); + StringAddStub stub(instr->hydrogen()->flags(), + isolate()->heap()->GetPretenureMode()); + CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); } diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 32b4b3e..655213e 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -1000,13 +1000,13 @@ Handle BinaryOpWithAllocationSiteStub::GenerateCode(Isolate* isolate) { template <> -HValue* CodeStubGraphBuilder::BuildCodeInitializedStub() { - NewStringAddStub* stub = casted_stub(); +HValue* CodeStubGraphBuilder::BuildCodeInitializedStub() { + StringAddStub* stub = casted_stub(); StringAddFlags flags = stub->flags(); PretenureFlag pretenure_flag = stub->pretenure_flag(); - HValue* left = GetParameter(NewStringAddStub::kLeft); - HValue* right = GetParameter(NewStringAddStub::kRight); + HValue* left = GetParameter(StringAddStub::kLeft); + HValue* right = GetParameter(StringAddStub::kRight); // Make sure that both arguments are strings if not known in advance. if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { @@ -1020,7 +1020,7 @@ HValue* CodeStubGraphBuilder::BuildCodeInitializedStub() { } -Handle NewStringAddStub::GenerateCode(Isolate* isolate) { +Handle StringAddStub::GenerateCode(Isolate* isolate) { return DoGenerateCode(isolate, this); } diff --git a/src/code-stubs.cc b/src/code-stubs.cc index da0a9b6..c5e00ea 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -269,8 +269,8 @@ void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime( } -void NewStringAddStub::PrintBaseName(StringStream* stream) { - stream->Add("NewStringAddStub"); +void StringAddStub::PrintBaseName(StringStream* stream) { + stream->Add("StringAddStub"); if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { stream->Add("_CheckBoth"); } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { @@ -781,8 +781,8 @@ void BinaryOpWithAllocationSiteStub::InstallDescriptors(Isolate* isolate) { // static -void NewStringAddStub::InstallDescriptors(Isolate* isolate) { - NewStringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED); +void StringAddStub::InstallDescriptors(Isolate* isolate) { + StringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED); InstallDescriptor(isolate, &stub); } diff --git a/src/code-stubs.h b/src/code-stubs.h index b08f982..df39b5c 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -45,7 +45,6 @@ namespace internal { V(BinaryOpICWithAllocationSite) \ V(BinaryOpWithAllocationSite) \ V(StringAdd) \ - V(NewStringAdd) \ V(SubString) \ V(StringCompare) \ V(Compare) \ @@ -447,19 +446,6 @@ class RuntimeCallHelper { }; -// TODO(bmeurer): Move to the StringAddStub declaration once we're -// done with the translation to a hydrogen code stub. -enum StringAddFlags { - // Omit both parameter checks. - STRING_ADD_CHECK_NONE = 0, - // Check left parameter. - STRING_ADD_CHECK_LEFT = 1 << 0, - // Check right parameter. - STRING_ADD_CHECK_RIGHT = 1 << 1, - // Check both parameters. - STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT -}; - } } // namespace v8::internal #if V8_TARGET_ARCH_IA32 @@ -1256,10 +1242,21 @@ class BinaryOpWithAllocationSiteStub V8_FINAL : public BinaryOpICStub { }; -// TODO(bmeurer): Rename to StringAddStub once we dropped the old StringAddStub. -class NewStringAddStub V8_FINAL : public HydrogenCodeStub { +enum StringAddFlags { + // Omit both parameter checks. + STRING_ADD_CHECK_NONE = 0, + // Check left parameter. + STRING_ADD_CHECK_LEFT = 1 << 0, + // Check right parameter. + STRING_ADD_CHECK_RIGHT = 1 << 1, + // Check both parameters. + STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT +}; + + +class StringAddStub V8_FINAL : public HydrogenCodeStub { public: - NewStringAddStub(StringAddFlags flags, PretenureFlag pretenure_flag) + StringAddStub(StringAddFlags flags, PretenureFlag pretenure_flag) : bit_field_(StringAddFlagsBits::encode(flags) | PretenureFlagBits::encode(pretenure_flag)) {} @@ -1292,12 +1289,12 @@ class NewStringAddStub V8_FINAL : public HydrogenCodeStub { class PretenureFlagBits: public BitField {}; uint32_t bit_field_; - virtual Major MajorKey() V8_OVERRIDE { return NewStringAdd; } + virtual Major MajorKey() V8_OVERRIDE { return StringAdd; } virtual int NotMissMinorKey() V8_OVERRIDE { return bit_field_; } virtual void PrintBaseName(StringStream* stream) V8_OVERRIDE; - DISALLOW_COPY_AND_ASSIGN(NewStringAddStub); + DISALLOW_COPY_AND_ASSIGN(StringAddStub); }; diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 1136daa..e0089e6 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -349,8 +349,6 @@ DEFINE_bool(omit_map_checks_for_leaf_maps, true, "do not emit check maps for constant values that have a leaf map, " "deoptimize the optimized code if the layout of the maps changes.") -DEFINE_bool(new_string_add, true, "enable new string addition") - // Profiler flags. DEFINE_int(frame_count, 1, "number of stack frames inspected by the profiler") // 0x1700 fits in the immediate field of an ARM instruction. diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index a2e6855..901f418 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -353,7 +353,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( } -void NewStringAddStub::InitializeInterfaceDescriptor( +void StringAddStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { static Register registers[] = { edx, eax }; @@ -3377,396 +3377,6 @@ void StringCharFromCodeGenerator::GenerateSlow( } -void StringAddStub::Generate(MacroAssembler* masm) { - Label call_runtime, call_builtin; - Builtins::JavaScript builtin_id = Builtins::ADD; - - // Load the two arguments. - __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. - __ mov(edx, Operand(esp, 1 * 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); - __ JumpIfSmi(eax, &call_runtime); - __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); - __ j(above_equal, &call_runtime); - - // First argument is a a string, test second. - __ JumpIfSmi(edx, &call_runtime); - __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); - __ j(above_equal, &call_runtime); - } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); - GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, - &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, 1 * kPointerSize, edx, ebx, ecx, edi, - &call_builtin); - builtin_id = Builtins::STRING_ADD_LEFT; - } - - // Both arguments are strings. - // eax: first string - // edx: second string - // Check if either of the strings are empty. In that case return the other. - Label second_not_zero_length, both_not_zero_length; - __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); - STATIC_ASSERT(kSmiTag == 0); - __ test(ecx, ecx); - __ j(not_zero, &second_not_zero_length, Label::kNear); - // Second string is empty, result is first string which is already in eax. - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - __ bind(&second_not_zero_length); - __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); - STATIC_ASSERT(kSmiTag == 0); - __ test(ebx, ebx); - __ j(not_zero, &both_not_zero_length, Label::kNear); - // First string is empty, result is second string which is in edx. - __ mov(eax, edx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // Both strings are non-empty. - // eax: first string - // ebx: length of first string as a smi - // ecx: length of second string as a smi - // edx: second string - // Look at the length of the result of adding the two strings. - Label string_add_flat_result, longer_than_two; - __ bind(&both_not_zero_length); - __ add(ebx, ecx); - STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); - // Handle exceptionally long strings in the runtime system. - __ j(overflow, &call_runtime); - // Use the string table when adding two one character strings, as it - // helps later optimizations to return an internalized string here. - __ cmp(ebx, Immediate(Smi::FromInt(2))); - __ j(not_equal, &longer_than_two); - - // Check that both strings are non-external ASCII strings. - __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); - - // Get the two characters forming the new string. - __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); - __ movzx_b(ecx, FieldOperand(edx, 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, make_two_character_string_no_reload; - StringHelper::GenerateTwoCharacterStringTableProbe( - masm, ebx, ecx, eax, edx, edi, - &make_two_character_string_no_reload, &make_two_character_string); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // Allocate a two character string. - __ bind(&make_two_character_string); - // Reload the arguments. - __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. - __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. - // Get the two characters forming the new string. - __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); - __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); - __ bind(&make_two_character_string_no_reload); - __ IncrementCounter(counters->string_add_make_two_char(), 1); - __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); - // Pack both characters in ebx. - __ shl(ecx, kBitsPerByte); - __ or_(ebx, ecx); - // Set the characters in the new string. - __ mov_w(FieldOperand(eax, SeqOneByteString::kHeaderSize), ebx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - __ bind(&longer_than_two); - // Check if resulting string will be flat. - __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); - __ j(below, &string_add_flat_result); - - // 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. - Label non_ascii, allocated, ascii_data; - __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); - __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); - __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); - __ and_(ecx, edi); - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ test(ecx, Immediate(kStringEncodingMask)); - __ j(zero, &non_ascii); - __ bind(&ascii_data); - // Allocate an ASCII cons string. - __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); - __ bind(&allocated); - // Fill the fields of the cons string. - __ AssertSmi(ebx); - __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); - __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), - Immediate(String::kEmptyHashField)); - - Label skip_write_barrier, after_writing; - ExternalReference high_promotion_mode = ExternalReference:: - new_space_high_promotion_mode_active_address(masm->isolate()); - __ test(Operand::StaticVariable(high_promotion_mode), Immediate(1)); - __ j(zero, &skip_write_barrier); - - __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); - __ RecordWriteField(ecx, - ConsString::kFirstOffset, - eax, - ebx, - kDontSaveFPRegs); - __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); - __ RecordWriteField(ecx, - ConsString::kSecondOffset, - edx, - ebx, - kDontSaveFPRegs); - __ jmp(&after_writing); - - __ bind(&skip_write_barrier); - __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); - __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); - - __ bind(&after_writing); - - __ mov(eax, ecx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - __ bind(&non_ascii); - // At least one of the strings is two-byte. Check whether it happens - // to contain only one byte characters. - // ecx: first instance type AND second instance type. - // edi: second instance type. - __ test(ecx, Immediate(kOneByteDataHintMask)); - __ j(not_zero, &ascii_data); - __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - __ xor_(edi, ecx); - STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); - __ and_(edi, kOneByteStringTag | kOneByteDataHintTag); - __ cmp(edi, kOneByteStringTag | kOneByteDataHintTag); - __ j(equal, &ascii_data); - // Allocate a two byte cons string. - __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); - __ jmp(&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. - // eax: first string - // ebx: length of resulting flat string as a smi - // edx: second string - Label first_prepared, second_prepared; - Label first_is_sequential, second_is_sequential; - __ bind(&string_add_flat_result); - __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - // ecx: instance type of first string - STATIC_ASSERT(kSeqStringTag == 0); - __ test_b(ecx, kStringRepresentationMask); - __ j(zero, &first_is_sequential, Label::kNear); - // Rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ test_b(ecx, kShortExternalStringMask); - __ j(not_zero, &call_runtime); - __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ jmp(&first_prepared, Label::kNear); - __ bind(&first_is_sequential); - __ add(eax, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - __ bind(&first_prepared); - - __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); - __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); - // Check whether both strings have same encoding. - // edi: instance type of second string - __ xor_(ecx, edi); - __ test_b(ecx, kStringEncodingMask); - __ j(not_zero, &call_runtime); - STATIC_ASSERT(kSeqStringTag == 0); - __ test_b(edi, kStringRepresentationMask); - __ j(zero, &second_is_sequential, Label::kNear); - // Rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ test_b(edi, kShortExternalStringMask); - __ j(not_zero, &call_runtime); - __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ jmp(&second_prepared, Label::kNear); - __ bind(&second_is_sequential); - __ add(edx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - __ bind(&second_prepared); - - // Push the addresses of both strings' first characters onto the stack. - __ push(edx); - __ push(eax); - - Label non_ascii_string_add_flat_result, call_runtime_drop_two; - // edi: instance type of second string - // First string and second string have the same encoding. - STATIC_ASSERT(kTwoByteStringTag == 0); - __ test_b(edi, kStringEncodingMask); - __ j(zero, &non_ascii_string_add_flat_result); - - // Both strings are ASCII strings. - // ebx: length of resulting flat string as a smi - __ SmiUntag(ebx); - __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); - // eax: result string - __ mov(ecx, eax); - // Locate first character of result. - __ add(ecx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - // Load first argument's length and first character location. Account for - // values currently on the stack when fetching arguments from it. - __ mov(edx, Operand(esp, 4 * kPointerSize)); - __ mov(edi, FieldOperand(edx, String::kLengthOffset)); - __ SmiUntag(edi); - __ pop(edx); - // eax: result string - // ecx: first character of result - // edx: first char of first argument - // edi: length of first argument - StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); - // Load second argument's length and first character location. Account for - // values currently on the stack when fetching arguments from it. - __ mov(edx, Operand(esp, 2 * kPointerSize)); - __ mov(edi, FieldOperand(edx, String::kLengthOffset)); - __ SmiUntag(edi); - __ pop(edx); - // eax: result string - // ecx: next character of result - // edx: first char of second argument - // edi: length of second argument - StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // Handle creating a flat two byte result. - // eax: first string - known to be two byte - // ebx: length of resulting flat string as a smi - // edx: second string - __ bind(&non_ascii_string_add_flat_result); - // Both strings are two byte strings. - __ SmiUntag(ebx); - __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); - // eax: result string - __ mov(ecx, eax); - // Locate first character of result. - __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // Load second argument's length and first character location. Account for - // values currently on the stack when fetching arguments from it. - __ mov(edx, Operand(esp, 4 * kPointerSize)); - __ mov(edi, FieldOperand(edx, String::kLengthOffset)); - __ SmiUntag(edi); - __ pop(edx); - // eax: result string - // ecx: first character of result - // edx: first char of first argument - // edi: length of first argument - StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); - // Load second argument's length and first character location. Account for - // values currently on the stack when fetching arguments from it. - __ mov(edx, Operand(esp, 2 * kPointerSize)); - __ mov(edi, FieldOperand(edx, String::kLengthOffset)); - __ SmiUntag(edi); - __ pop(edx); - // eax: result string - // ecx: next character of result - // edx: first char of second argument - // edi: length of second argument - StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // Recover stack pointer before jumping to runtime. - __ bind(&call_runtime_drop_two); - __ Drop(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(eax); - __ push(edx); -} - - -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, - Register temp) { - __ pop(temp); - __ pop(edx); - __ pop(eax); - __ push(temp); -} - - -void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* slow) { - // First check if the argument is already a string. - Label not_string, done; - __ JumpIfSmi(arg, ¬_string); - __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); - __ j(below, &done); - - // Check the number to string cache. - __ bind(¬_string); - // Puts the cached result into scratch1. - __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); - __ mov(arg, scratch1); - __ mov(Operand(esp, stack_offset), arg); - __ bind(&done); -} - - -void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii) { - Label loop; - __ bind(&loop); - // This loop just copies one character at a time, as it is only used for very - // short strings. - if (ascii) { - __ mov_b(scratch, Operand(src, 0)); - __ mov_b(Operand(dest, 0), scratch); - __ add(src, Immediate(1)); - __ add(dest, Immediate(1)); - } else { - __ mov_w(scratch, Operand(src, 0)); - __ mov_w(Operand(dest, 0), scratch); - __ add(src, Immediate(2)); - __ add(dest, Immediate(2)); - } - __ sub(count, Immediate(1)); - __ j(not_zero, &loop); -} - - void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, Register dest, Register src, @@ -3827,128 +3437,6 @@ void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, } -void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Label* not_probed, - Label* not_found) { - // Register scratch3 is the general scratch register in this function. - Register scratch = scratch3; - - // Make sure that both characters are not digits as such strings has a - // different hash algorithm. Don't try to look for these in the string table. - Label not_array_index; - __ mov(scratch, c1); - __ sub(scratch, Immediate(static_cast('0'))); - __ cmp(scratch, Immediate(static_cast('9' - '0'))); - __ j(above, ¬_array_index, Label::kNear); - __ mov(scratch, c2); - __ sub(scratch, Immediate(static_cast('0'))); - __ cmp(scratch, Immediate(static_cast('9' - '0'))); - __ j(below_equal, not_probed); - - __ bind(¬_array_index); - // Calculate the two character string hash. - Register hash = scratch1; - GenerateHashInit(masm, hash, c1, scratch); - GenerateHashAddCharacter(masm, hash, c2, scratch); - GenerateHashGetHash(masm, hash, scratch); - - // Collect the two characters in a register. - Register chars = c1; - __ shl(c2, kBitsPerByte); - __ or_(chars, c2); - - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string. - - // Load the string table. - Register string_table = c2; - __ LoadRoot(string_table, Heap::kStringTableRootIndex); - - // Calculate capacity mask from the string table capacity. - Register mask = scratch2; - __ mov(mask, FieldOperand(string_table, StringTable::kCapacityOffset)); - __ SmiUntag(mask); - __ sub(mask, Immediate(1)); - - // Registers - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string - // string_table: string table - // mask: capacity mask - // scratch: - - - // Perform a number of probes in the string table. - static const int kProbes = 4; - Label found_in_string_table; - Label next_probe[kProbes], next_probe_pop_mask[kProbes]; - Register candidate = scratch; // Scratch register contains candidate. - for (int i = 0; i < kProbes; i++) { - // Calculate entry in string table. - __ mov(scratch, hash); - if (i > 0) { - __ add(scratch, Immediate(StringTable::GetProbeOffset(i))); - } - __ and_(scratch, mask); - - // Load the entry from the string table. - STATIC_ASSERT(StringTable::kEntrySize == 1); - __ mov(candidate, - FieldOperand(string_table, - scratch, - times_pointer_size, - StringTable::kElementsStartOffset)); - - // If entry is undefined no string with this hash can be found. - Factory* factory = masm->isolate()->factory(); - __ cmp(candidate, factory->undefined_value()); - __ j(equal, not_found); - __ cmp(candidate, factory->the_hole_value()); - __ j(equal, &next_probe[i]); - - // If length is not 2 the string is not a candidate. - __ cmp(FieldOperand(candidate, String::kLengthOffset), - Immediate(Smi::FromInt(2))); - __ j(not_equal, &next_probe[i]); - - // As we are out of registers save the mask on the stack and use that - // register as a temporary. - __ push(mask); - Register temp = mask; - - // Check that the candidate is a non-external ASCII string. - __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); - __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); - __ JumpIfInstanceTypeIsNotSequentialAscii( - temp, temp, &next_probe_pop_mask[i]); - - // Check if the two characters match. - __ mov(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); - __ and_(temp, 0x0000ffff); - __ cmp(chars, temp); - __ j(equal, &found_in_string_table); - __ bind(&next_probe_pop_mask[i]); - __ pop(mask); - __ bind(&next_probe[i]); - } - - // No matching 2 character string found by probing. - __ jmp(not_found); - - // Scratch register contains result when we fall through to here. - Register result = candidate; - __ bind(&found_in_string_table); - __ pop(mask); // Pop saved mask from the stack. - if (!result.is(eax)) { - __ mov(eax, result); - } -} - - void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character, diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h index 0982fe1..e383a9d 100644 --- a/src/ia32/code-stubs-ia32.h +++ b/src/ia32/code-stubs-ia32.h @@ -63,17 +63,6 @@ class StoreBufferOverflowStub: public PlatformCodeStub { class StringHelper : public AllStatic { public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersREP adds too much - // overhead. Copying of overlapping regions is not supported. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); - // Generate code for copying characters using the rep movs instruction. // Copies ecx characters from esi to edi. Copying of overlapping regions is // not supported. @@ -84,23 +73,6 @@ class StringHelper : public AllStatic { Register scratch, // Neither of above. bool ascii); - // Probe the string table for a two character string. If the string - // requires non-standard hashing a jump to the label not_probed is - // performed and registers c1 and c2 are preserved. In all other - // cases they are clobbered. If the string is not found by probing a - // jump to the label not_found is performed. This jump does not - // guarantee that the string is not in the string table. If the - // string is found the code falls through with the string in - // register eax. - static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Label* not_probed, - Label* not_found); - // Generate string hash. static void GenerateHashInit(MacroAssembler* masm, Register hash, @@ -119,31 +91,6 @@ class StringHelper : public AllStatic { }; -class StringAddStub: public PlatformCodeStub { - public: - explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} - - private: - Major MajorKey() { return StringAdd; } - int MinorKey() { return flags_; } - - void Generate(MacroAssembler* masm); - - void GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* slow); - - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp); - - const StringAddFlags flags_; -}; - - class SubStringStub: public PlatformCodeStub { public: SubStringStub() {} diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 4422e4e..0f6c851 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -3636,21 +3636,12 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { ZoneList* args = expr->arguments(); ASSERT_EQ(2, args->length()); + VisitForStackValue(args->at(0)); + VisitForAccumulatorValue(args->at(1)); - if (FLAG_new_string_add) { - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - - __ pop(edx); - NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); - __ CallStub(&stub); - } else { - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); - - StringAddStub stub(STRING_ADD_CHECK_BOTH); - __ CallStub(&stub); - } + __ pop(edx); + StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); + __ CallStub(&stub); context()->Plug(eax); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index fc47c50..d3b9d5b 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -4907,18 +4907,11 @@ void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { void LCodeGen::DoStringAdd(LStringAdd* instr) { ASSERT(ToRegister(instr->context()).is(esi)); - if (FLAG_new_string_add) { - ASSERT(ToRegister(instr->left()).is(edx)); - ASSERT(ToRegister(instr->right()).is(eax)); - NewStringAddStub stub(instr->hydrogen()->flags(), - instr->hydrogen()->pretenure_flag()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } else { - EmitPushTaggedOperand(instr->left()); - EmitPushTaggedOperand(instr->right()); - StringAddStub stub(instr->hydrogen()->flags()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } + ASSERT(ToRegister(instr->left()).is(edx)); + ASSERT(ToRegister(instr->right()).is(eax)); + StringAddStub stub(instr->hydrogen()->flags(), + instr->hydrogen()->pretenure_flag()); + CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index b375893..b4b4452 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2378,12 +2378,8 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { LOperand* context = UseFixed(instr->context(), esi); - LOperand* left = FLAG_new_string_add - ? UseFixed(instr->left(), edx) - : UseOrConstantAtStart(instr->left()); - LOperand* right = FLAG_new_string_add - ? UseFixed(instr->right(), eax) - : UseOrConstantAtStart(instr->right()); + LOperand* left = UseFixed(instr->left(), edx); + LOperand* right = UseFixed(instr->right(), eax); LStringAdd* string_add = new(zone()) LStringAdd(context, left, right); return MarkAsCall(DefineFixed(string_add, eax), instr); } diff --git a/src/isolate.cc b/src/isolate.cc index bc24b71..2c2c082 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -2112,7 +2112,7 @@ bool Isolate::Init(Deserializer* des) { InternalArrayConstructorStubBase::InstallDescriptors(this); FastNewClosureStub::InstallDescriptors(this); NumberToStringStub::InstallDescriptors(this); - NewStringAddStub::InstallDescriptors(this); + StringAddStub::InstallDescriptors(this); } CallDescriptors::InitializeForIsolate(this); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index f44f114..3bd381a 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 }; @@ -3625,33 +3625,6 @@ void StringCharFromCodeGenerator::GenerateSlow( } -void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii) { - Label loop; - Label done; - // This loop just copies one character at a time, as it is only used for - // very short strings. - if (!ascii) { - __ addu(count, count, count); - } - __ Branch(&done, eq, count, Operand(zero_reg)); - __ addu(count, dest, count); // Count now points to the last dest byte. - - __ bind(&loop); - __ lbu(scratch, MemOperand(src)); - __ addiu(src, src, 1); - __ sb(scratch, MemOperand(dest)); - __ addiu(dest, dest, 1); - __ Branch(&loop, lt, dest, Operand(count)); - - __ bind(&done); -} - - enum CopyCharactersFlags { COPY_ASCII = 1, DEST_ALWAYS_ALIGNED = 2 @@ -3770,145 +3743,6 @@ void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, } -void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found) { - // Register scratch3 is the general scratch register in this function. - Register scratch = scratch3; - - // Make sure that both characters are not digits as such strings has a - // different hash algorithm. Don't try to look for these in the string table. - Label not_array_index; - __ Subu(scratch, c1, Operand(static_cast('0'))); - __ Branch(¬_array_index, - Ugreater, - scratch, - Operand(static_cast('9' - '0'))); - __ Subu(scratch, c2, Operand(static_cast('0'))); - - // If check failed combine both characters into single halfword. - // This is required by the contract of the method: code at the - // not_found branch expects this combination in c1 register. - Label tmp; - __ sll(scratch1, c2, kBitsPerByte); - __ Branch(&tmp, Ugreater, scratch, Operand(static_cast('9' - '0'))); - __ Or(c1, c1, scratch1); - __ bind(&tmp); - __ Branch( - not_found, Uless_equal, scratch, Operand(static_cast('9' - '0'))); - - __ bind(¬_array_index); - // Calculate the two character string hash. - Register hash = scratch1; - StringHelper::GenerateHashInit(masm, hash, c1); - StringHelper::GenerateHashAddCharacter(masm, hash, c2); - StringHelper::GenerateHashGetHash(masm, hash); - - // Collect the two characters in a register. - Register chars = c1; - __ sll(scratch, c2, kBitsPerByte); - __ Or(chars, chars, scratch); - - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string. - - // Load string table. - // Load address of first element of the string table. - Register string_table = c2; - __ LoadRoot(string_table, Heap::kStringTableRootIndex); - - Register undefined = scratch4; - __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); - - // Calculate capacity mask from the string table capacity. - Register mask = scratch2; - __ lw(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset)); - __ sra(mask, mask, 1); - __ Addu(mask, mask, -1); - - // Calculate untagged address of the first element of the string table. - Register first_string_table_element = string_table; - __ Addu(first_string_table_element, string_table, - Operand(StringTable::kElementsStartOffset - kHeapObjectTag)); - - // Registers. - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string - // mask: capacity mask - // first_string_table_element: address of the first element of - // the string table - // undefined: the undefined object - // scratch: - - - // Perform a number of probes in the string table. - const int kProbes = 4; - Label found_in_string_table; - Label next_probe[kProbes]; - Register candidate = scratch5; // Scratch register contains candidate. - for (int i = 0; i < kProbes; i++) { - // Calculate entry in string table. - if (i > 0) { - __ Addu(candidate, hash, Operand(StringTable::GetProbeOffset(i))); - } else { - __ mov(candidate, hash); - } - - __ And(candidate, candidate, Operand(mask)); - - // Load the entry from the symble table. - STATIC_ASSERT(StringTable::kEntrySize == 1); - __ sll(scratch, candidate, kPointerSizeLog2); - __ Addu(scratch, scratch, first_string_table_element); - __ lw(candidate, MemOperand(scratch)); - - // If entry is undefined no string with this hash can be found. - Label is_string; - __ GetObjectType(candidate, scratch, scratch); - __ Branch(&is_string, ne, scratch, Operand(ODDBALL_TYPE)); - - __ Branch(not_found, eq, undefined, Operand(candidate)); - // Must be the hole (deleted entry). - if (FLAG_debug_code) { - __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole, - scratch, Operand(candidate)); - } - __ jmp(&next_probe[i]); - - __ bind(&is_string); - - // Check that the candidate is a non-external ASCII string. The instance - // type is still in the scratch register from the CompareObjectType - // operation. - __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]); - - // If length is not 2 the string is not a candidate. - __ lw(scratch, FieldMemOperand(candidate, String::kLengthOffset)); - __ Branch(&next_probe[i], ne, scratch, Operand(Smi::FromInt(2))); - - // Check if the two characters match. - // Assumes that word load is little endian. - __ lhu(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); - __ Branch(&found_in_string_table, eq, chars, Operand(scratch)); - __ bind(&next_probe[i]); - } - - // No matching 2 character string found by probing. - __ jmp(not_found); - - // Scratch register contains result when we fall through to here. - Register result = candidate; - __ bind(&found_in_string_table); - __ mov(v0, result); -} - - void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character) { @@ -4565,355 +4399,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; diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h index 3019220..8d65d5b 100644 --- a/src/mips/code-stubs-mips.h +++ b/src/mips/code-stubs-mips.h @@ -58,18 +58,6 @@ class StoreBufferOverflowStub: public PlatformCodeStub { class StringHelper : public AllStatic { public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersLong adds too much - // overhead. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); - // Generate code for copying a large number of characters. This function // is allowed to spend extra time setting up conditions to make copying // faster. Copying of overlapping regions is not supported. @@ -86,23 +74,6 @@ class StringHelper : public AllStatic { int flags); - // Probe the string table for a two character string. If the string is - // not found by probing a jump to the label not_found is performed. This jump - // does not guarantee that the string is not in the string table. If the - // string is found the code falls through with the string in register r0. - // Contents of both c1 and c2 registers are modified. At the exit c1 is - // guaranteed to contain halfword with low and high bytes equal to - // initial contents of c1 and c2 respectively. - static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found); - // Generate string hash. static void GenerateHashInit(MacroAssembler* masm, Register hash, @@ -120,32 +91,6 @@ class StringHelper : public AllStatic { }; -class StringAddStub: public PlatformCodeStub { - public: - explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} - - private: - Major MajorKey() { return StringAdd; } - int MinorKey() { return flags_; } - - void Generate(MacroAssembler* masm); - - void GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Label* slow); - - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateRegisterArgsPop(MacroAssembler* masm); - - const StringAddFlags flags_; -}; - - class SubStringStub: public PlatformCodeStub { public: SubStringStub() {} diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 1956e42..77708cd 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -3730,21 +3730,13 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { ZoneList* args = expr->arguments(); ASSERT_EQ(2, args->length()); - if (FLAG_new_string_add) { - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - - __ pop(a1); - __ mov(a0, result_register()); // NewStringAddStub requires args in a0, a1. - NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); - __ CallStub(&stub); - } else { - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); + VisitForStackValue(args->at(0)); + VisitForAccumulatorValue(args->at(1)); - StringAddStub stub(STRING_ADD_CHECK_BOTH); - __ CallStub(&stub); - } + __ pop(a1); + __ mov(a0, result_register()); // StringAddStub requires args in a0, a1. + StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); + __ CallStub(&stub); context()->Plug(v0); } diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index aed2a28..00954b8 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -4444,18 +4444,11 @@ void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { void LCodeGen::DoStringAdd(LStringAdd* instr) { ASSERT(ToRegister(instr->context()).is(cp)); - if (FLAG_new_string_add) { - ASSERT(ToRegister(instr->left()).is(a1)); - ASSERT(ToRegister(instr->right()).is(a0)); - NewStringAddStub stub(instr->hydrogen()->flags(), - isolate()->heap()->GetPretenureMode()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } else { - __ push(ToRegister(instr->left())); - __ push(ToRegister(instr->right())); - StringAddStub stub(instr->hydrogen()->flags()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } + ASSERT(ToRegister(instr->left()).is(a1)); + ASSERT(ToRegister(instr->right()).is(a0)); + StringAddStub stub(instr->hydrogen()->flags(), + isolate()->heap()->GetPretenureMode()); + CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 0a14c3e..1615d4a 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -2205,12 +2205,8 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { LOperand* context = UseFixed(instr->context(), cp); - LOperand* left = FLAG_new_string_add - ? UseFixed(instr->left(), a1) - : UseRegisterAtStart(instr->left()); - LOperand* right = FLAG_new_string_add - ? UseFixed(instr->right(), a0) - : UseRegisterAtStart(instr->right()); + LOperand* left = UseFixed(instr->left(), a1); + LOperand* right = UseFixed(instr->right(), a0); return MarkAsCall( DefineFixed(new(zone()) LStringAdd(context, left, right), v0), instr); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 1e68bdf..63076dc 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -350,7 +350,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( } -void NewStringAddStub::InitializeInterfaceDescriptor( +void StringAddStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { static Register registers[] = { rdx, rax }; @@ -3244,365 +3244,6 @@ void StringCharFromCodeGenerator::GenerateSlow( } -void StringAddStub::Generate(MacroAssembler* masm) { - Label call_runtime, call_builtin; - Builtins::JavaScript builtin_id = Builtins::ADD; - - // Load the two arguments. - StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); - __ movp(rax, args.GetArgumentOperand(0)); // First argument (left). - __ movp(rdx, args.GetArgumentOperand(1)); // Second argument (right). - - // 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); - __ JumpIfSmi(rax, &call_runtime); - __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); - __ j(above_equal, &call_runtime); - - // First argument is a a string, test second. - __ JumpIfSmi(rdx, &call_runtime); - __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); - __ j(above_equal, &call_runtime); - } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); - GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, - &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, 1 * kPointerSize, rdx, rbx, rcx, rdi, - &call_builtin); - builtin_id = Builtins::STRING_ADD_LEFT; - } - - // Both arguments are strings. - // rax: first string - // rdx: second string - // Check if either of the strings are empty. In that case return the other. - Label second_not_zero_length, both_not_zero_length; - __ movp(rcx, FieldOperand(rdx, String::kLengthOffset)); - __ SmiTest(rcx); - __ j(not_zero, &second_not_zero_length, Label::kNear); - // Second string is empty, result is first string which is already in rax. - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - __ bind(&second_not_zero_length); - __ movp(rbx, FieldOperand(rax, String::kLengthOffset)); - __ SmiTest(rbx); - __ j(not_zero, &both_not_zero_length, Label::kNear); - // First string is empty, result is second string which is in rdx. - __ movp(rax, rdx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // Both strings are non-empty. - // rax: first string - // rbx: length of first string - // rcx: length of second string - // rdx: second string - // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) - // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) - Label string_add_flat_result, longer_than_two; - __ bind(&both_not_zero_length); - - // If arguments where known to be strings, maps are not loaded to r8 and r9 - // by the code above. - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { - __ movp(r8, FieldOperand(rax, HeapObject::kMapOffset)); - __ movp(r9, FieldOperand(rdx, HeapObject::kMapOffset)); - } - // Get the instance types of the two strings as they will be needed soon. - __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); - __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); - - // Look at the length of the result of adding the two strings. - STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); - __ SmiAdd(rbx, rbx, rcx); - // Use the string table when adding two one character strings, as it - // helps later optimizations to return an internalized string here. - __ SmiCompare(rbx, Smi::FromInt(2)); - __ j(not_equal, &longer_than_two); - - // Check that both strings are non-external ASCII strings. - __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, - &call_runtime); - - // Get the two characters forming the sub string. - __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); - __ movzxbq(rcx, FieldOperand(rdx, 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, make_flat_ascii_string; - StringHelper::GenerateTwoCharacterStringTableProbe( - masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - __ bind(&make_two_character_string); - __ Set(rdi, 2); - __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime); - // rbx - first byte: first character - // rbx - second byte: *maybe* second character - // Make sure that the second byte of rbx contains the second character. - __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); - __ shll(rcx, Immediate(kBitsPerByte)); - __ orl(rbx, rcx); - // Write both characters to the new string. - __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - __ bind(&longer_than_two); - // Check if resulting string will be flat. - __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength)); - __ j(below, &string_add_flat_result); - // Handle exceptionally long strings in the runtime system. - STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); - __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); - __ j(above, &call_runtime); - - // 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. - // rax: first string - // rbx: length of resulting flat string - // rdx: second string - // r8: instance type of first string - // r9: instance type of second string - Label non_ascii, allocated, ascii_data; - __ movl(rcx, r8); - __ and_(rcx, r9); - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ testl(rcx, Immediate(kStringEncodingMask)); - __ j(zero, &non_ascii); - __ bind(&ascii_data); - // Allocate an ASCII cons string. - __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime); - __ bind(&allocated); - // Fill the fields of the cons string. - __ movp(FieldOperand(rcx, ConsString::kLengthOffset), rbx); - __ movp(FieldOperand(rcx, ConsString::kHashFieldOffset), - Immediate(String::kEmptyHashField)); - - Label skip_write_barrier, after_writing; - ExternalReference high_promotion_mode = ExternalReference:: - new_space_high_promotion_mode_active_address(masm->isolate()); - __ Load(rbx, high_promotion_mode); - __ testb(rbx, Immediate(1)); - __ j(zero, &skip_write_barrier); - - __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax); - __ RecordWriteField(rcx, - ConsString::kFirstOffset, - rax, - rbx, - kDontSaveFPRegs); - __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx); - __ RecordWriteField(rcx, - ConsString::kSecondOffset, - rdx, - rbx, - kDontSaveFPRegs); - __ jmp(&after_writing); - - __ bind(&skip_write_barrier); - __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax); - __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx); - - __ bind(&after_writing); - - __ movp(rax, rcx); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - __ bind(&non_ascii); - // At least one of the strings is two-byte. Check whether it happens - // to contain only one byte characters. - // rcx: first instance type AND second instance type. - // r8: first instance type. - // r9: second instance type. - __ testb(rcx, Immediate(kOneByteDataHintMask)); - __ j(not_zero, &ascii_data); - __ xor_(r8, r9); - STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); - __ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); - __ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); - __ j(equal, &ascii_data); - // Allocate a two byte cons string. - __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); - __ jmp(&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. - // rax: first string - // rbx: length of resulting flat string as smi - // rdx: second string - // r8: instance type of first string - // r9: instance type of first string - Label first_prepared, second_prepared; - Label first_is_sequential, second_is_sequential; - __ bind(&string_add_flat_result); - - __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset)); - // r14: length of first string - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(r8, Immediate(kStringRepresentationMask)); - __ j(zero, &first_is_sequential, Label::kNear); - // Rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ testb(r8, Immediate(kShortExternalStringMask)); - __ j(not_zero, &call_runtime); - __ movp(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); - __ jmp(&first_prepared, Label::kNear); - __ bind(&first_is_sequential); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); - __ bind(&first_prepared); - - // Check whether both strings have same encoding. - __ xorl(r8, r9); - __ testb(r8, Immediate(kStringEncodingMask)); - __ j(not_zero, &call_runtime); - - __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset)); - // r15: length of second string - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(r9, Immediate(kStringRepresentationMask)); - __ j(zero, &second_is_sequential, Label::kNear); - // Rule out short external string and load string resource. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ testb(r9, Immediate(kShortExternalStringMask)); - __ j(not_zero, &call_runtime); - __ movp(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); - __ jmp(&second_prepared, Label::kNear); - __ bind(&second_is_sequential); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); - __ bind(&second_prepared); - - Label non_ascii_string_add_flat_result; - // r9: instance type of second string - // First string and second string have the same encoding. - STATIC_ASSERT(kTwoByteStringTag == 0); - __ SmiToInteger32(rbx, rbx); - __ testb(r9, Immediate(kStringEncodingMask)); - __ j(zero, &non_ascii_string_add_flat_result); - - __ bind(&make_flat_ascii_string); - // Both strings are ASCII strings. As they are short they are both flat. - __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); - // rax: result string - // Locate first character of result. - __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); - // rcx: first char of first string - // rbx: first character of result - // r14: length of first string - StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true); - // rbx: next character of result - // rdx: first char of second string - // r15: length of second string - StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - __ bind(&non_ascii_string_add_flat_result); - // Both strings are ASCII strings. As they are short they are both flat. - __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime); - // rax: result string - // Locate first character of result. - __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); - // rcx: first char of first string - // rbx: first character of result - // r14: length of first string - StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false); - // rbx: next character of result - // rdx: first char of second string - // r15: length of second string - StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); - __ IncrementCounter(counters->string_add_native(), 1); - __ ret(2 * kPointerSize); - - // 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(rax); - __ push(rdx); -} - - -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, - Register temp) { - __ PopReturnAddressTo(temp); - __ pop(rdx); - __ pop(rax); - __ PushReturnAddressFrom(temp); -} - - -void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* slow) { - // First check if the argument is already a string. - Label not_string, done; - __ JumpIfSmi(arg, ¬_string); - __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); - __ j(below, &done); - - // Check the number to string cache. - __ bind(¬_string); - // Puts the cached result into scratch1. - __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); - __ movp(arg, scratch1); - __ movp(Operand(rsp, stack_offset), arg); - __ bind(&done); -} - - -void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - bool ascii) { - Label loop; - __ bind(&loop); - // This loop just copies one character at a time, as it is only used for very - // short strings. - if (ascii) { - __ movb(kScratchRegister, Operand(src, 0)); - __ movb(Operand(dest, 0), kScratchRegister); - __ incq(src); - __ incq(dest); - } else { - __ movzxwl(kScratchRegister, Operand(src, 0)); - __ movw(Operand(dest, 0), kScratchRegister); - __ addq(src, Immediate(2)); - __ addq(dest, Immediate(2)); - } - __ decl(count); - __ j(not_zero, &loop); -} - - void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, Register dest, Register src, @@ -3659,133 +3300,6 @@ void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, __ bind(&done); } -void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Label* not_found) { - // Register scratch3 is the general scratch register in this function. - Register scratch = scratch3; - - // Make sure that both characters are not digits as such strings has a - // different hash algorithm. Don't try to look for these in the string table. - Label not_array_index; - __ leal(scratch, Operand(c1, -'0')); - __ cmpl(scratch, Immediate(static_cast('9' - '0'))); - __ j(above, ¬_array_index, Label::kNear); - __ leal(scratch, Operand(c2, -'0')); - __ cmpl(scratch, Immediate(static_cast('9' - '0'))); - __ j(below_equal, not_found); - - __ bind(¬_array_index); - // Calculate the two character string hash. - Register hash = scratch1; - GenerateHashInit(masm, hash, c1, scratch); - GenerateHashAddCharacter(masm, hash, c2, scratch); - GenerateHashGetHash(masm, hash, scratch); - - // Collect the two characters in a register. - Register chars = c1; - __ shl(c2, Immediate(kBitsPerByte)); - __ orl(chars, c2); - - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string. - - // Load the string table. - Register string_table = c2; - __ LoadRoot(string_table, Heap::kStringTableRootIndex); - - // Calculate capacity mask from the string table capacity. - Register mask = scratch2; - __ SmiToInteger32(mask, - FieldOperand(string_table, StringTable::kCapacityOffset)); - __ decl(mask); - - Register map = scratch4; - - // Registers - // chars: two character string, char 1 in byte 0 and char 2 in byte 1. - // hash: hash of two character string (32-bit int) - // string_table: string table - // mask: capacity mask (32-bit int) - // map: - - // scratch: - - - // Perform a number of probes in the string table. - static const int kProbes = 4; - Label found_in_string_table; - Label next_probe[kProbes]; - Register candidate = scratch; // Scratch register contains candidate. - for (int i = 0; i < kProbes; i++) { - // Calculate entry in string table. - __ movl(scratch, hash); - if (i > 0) { - __ addl(scratch, Immediate(StringTable::GetProbeOffset(i))); - } - __ andl(scratch, mask); - - // Load the entry from the string table. - STATIC_ASSERT(StringTable::kEntrySize == 1); - __ movp(candidate, - FieldOperand(string_table, - scratch, - times_pointer_size, - StringTable::kElementsStartOffset)); - - // If entry is undefined no string with this hash can be found. - Label is_string; - __ CmpObjectType(candidate, ODDBALL_TYPE, map); - __ j(not_equal, &is_string, Label::kNear); - - __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); - __ j(equal, not_found); - // Must be the hole (deleted entry). - if (FLAG_debug_code) { - __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); - __ cmpq(kScratchRegister, candidate); - __ Assert(equal, kOddballInStringTableIsNotUndefinedOrTheHole); - } - __ jmp(&next_probe[i]); - - __ bind(&is_string); - - // If length is not 2 the string is not a candidate. - __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), - Smi::FromInt(2)); - __ j(not_equal, &next_probe[i]); - - // We use kScratchRegister as a temporary register in assumption that - // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly - Register temp = kScratchRegister; - - // Check that the candidate is a non-external ASCII string. - __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); - __ JumpIfInstanceTypeIsNotSequentialAscii( - temp, temp, &next_probe[i]); - - // Check if the two characters match. - __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); - __ andl(temp, Immediate(0x0000ffff)); - __ cmpl(chars, temp); - __ j(equal, &found_in_string_table); - __ bind(&next_probe[i]); - } - - // No matching 2 character string found by probing. - __ jmp(not_found); - - // Scratch register contains result when we fall through to here. - Register result = candidate; - __ bind(&found_in_string_table); - if (!result.is(rax)) { - __ movp(rax, result); - } -} - void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h index fb05ff7..c65307a 100644 --- a/src/x64/code-stubs-x64.h +++ b/src/x64/code-stubs-x64.h @@ -56,16 +56,6 @@ class StoreBufferOverflowStub: public PlatformCodeStub { class StringHelper : public AllStatic { public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersREP adds too much - // overhead. Copying of overlapping regions is not supported. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - bool ascii); - // Generate code for copying characters using the rep movs instruction. // Copies rcx characters from rsi to rdi. Copying of overlapping regions is // not supported. @@ -76,19 +66,6 @@ class StringHelper : public AllStatic { bool ascii); - // Probe the string table for a two character string. If the string is - // not found by probing a jump to the label not_found is performed. This jump - // does not guarantee that the string is not in the string table. If the - // string is found the code falls through with the string in register rax. - static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Label* not_found); - // Generate string hash. static void GenerateHashInit(MacroAssembler* masm, Register hash, @@ -107,31 +84,6 @@ class StringHelper : public AllStatic { }; -class StringAddStub: public PlatformCodeStub { - public: - explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} - - private: - Major MajorKey() { return StringAdd; } - int MinorKey() { return flags_; } - - void Generate(MacroAssembler* masm); - - void GenerateConvertArgument(MacroAssembler* masm, - int stack_offset, - Register arg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* slow); - - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp); - - const StringAddFlags flags_; -}; - - class SubStringStub: public PlatformCodeStub { public: SubStringStub() {} diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 5061089..fb382d1 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -3610,21 +3610,12 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { ZoneList* args = expr->arguments(); ASSERT_EQ(2, args->length()); + VisitForStackValue(args->at(0)); + VisitForAccumulatorValue(args->at(1)); - if (FLAG_new_string_add) { - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - - __ pop(rdx); - NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); - __ CallStub(&stub); - } else { - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); - - StringAddStub stub(STRING_ADD_CHECK_BOTH); - __ CallStub(&stub); - } + __ pop(rdx); + StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); + __ CallStub(&stub); context()->Plug(rax); } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 178e9d1..30f6e05 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -4388,18 +4388,11 @@ void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { void LCodeGen::DoStringAdd(LStringAdd* instr) { ASSERT(ToRegister(instr->context()).is(rsi)); - if (FLAG_new_string_add) { - ASSERT(ToRegister(instr->left()).is(rdx)); - ASSERT(ToRegister(instr->right()).is(rax)); - NewStringAddStub stub(instr->hydrogen()->flags(), - isolate()->heap()->GetPretenureMode()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } else { - EmitPushTaggedOperand(instr->left()); - EmitPushTaggedOperand(instr->right()); - StringAddStub stub(instr->hydrogen()->flags()); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); - } + ASSERT(ToRegister(instr->left()).is(rdx)); + ASSERT(ToRegister(instr->right()).is(rax)); + StringAddStub stub(instr->hydrogen()->flags(), + isolate()->heap()->GetPretenureMode()); + CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index d4e29f6..49f7b64 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2228,12 +2228,8 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { LOperand* context = UseFixed(instr->context(), rsi); - LOperand* left = FLAG_new_string_add - ? UseFixed(instr->left(), rdx) - : UseOrConstantAtStart(instr->left()); - LOperand* right = FLAG_new_string_add - ? UseFixed(instr->right(), rax) - : UseOrConstantAtStart(instr->right()); + LOperand* left = UseFixed(instr->left(), rdx); + LOperand* right = UseFixed(instr->right(), rax); return MarkAsCall( DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr); } -- 2.7.4