Index: src/ia32/code-stubs-ia32.cc |
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc |
index a2e6855b744b0d7ab4cc0abae744ba7c1f1318d9..901f41837db1f8625aa56b6dc6eb70a9ea9bcbf5 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<int>('0'))); |
- __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); |
- __ j(above, ¬_array_index, Label::kNear); |
- __ mov(scratch, c2); |
- __ sub(scratch, Immediate(static_cast<int>('0'))); |
- __ cmp(scratch, Immediate(static_cast<int>('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, |