OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3904 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3915 | 3915 |
3916 // There is no virtual frame effect from here up to the final result | 3916 // There is no virtual frame effect from here up to the final result |
3917 // push. | 3917 // push. |
3918 | 3918 |
3919 // If the receiver is a smi trigger the slow case. | 3919 // If the receiver is a smi trigger the slow case. |
3920 __ JumpIfSmi(object.reg(), &slow_case); | 3920 __ JumpIfSmi(object.reg(), &slow_case); |
3921 | 3921 |
3922 // If the index is negative or non-smi trigger the slow case. | 3922 // If the index is negative or non-smi trigger the slow case. |
3923 __ JumpIfNotPositiveSmi(index.reg(), &slow_case); | 3923 __ JumpIfNotPositiveSmi(index.reg(), &slow_case); |
3924 | 3924 |
| 3925 // Untag the index. |
| 3926 __ SmiToInteger32(index.reg(), index.reg()); |
| 3927 |
3925 __ bind(&try_again_with_new_string); | 3928 __ bind(&try_again_with_new_string); |
3926 // Fetch the instance type of the receiver into rcx. | 3929 // Fetch the instance type of the receiver into rcx. |
3927 __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset)); | 3930 __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset)); |
3928 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); | 3931 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); |
3929 // If the receiver is not a string trigger the slow case. | 3932 // If the receiver is not a string trigger the slow case. |
3930 __ testb(rcx, Immediate(kIsNotStringMask)); | 3933 __ testb(rcx, Immediate(kIsNotStringMask)); |
3931 __ j(not_zero, &slow_case); | 3934 __ j(not_zero, &slow_case); |
3932 | 3935 |
3933 // Check for index out of range. | 3936 // Check for index out of range. |
3934 __ SmiCompare(index.reg(), FieldOperand(object.reg(), String::kLengthOffset)); | 3937 __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset)); |
3935 __ j(greater_equal, &slow_case); | 3938 __ j(greater_equal, &slow_case); |
3936 // Reload the instance type (into the temp register this time).. | 3939 // Reload the instance type (into the temp register this time).. |
3937 __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); | 3940 __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
3938 __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); | 3941 __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
3939 | 3942 |
3940 // We need special handling for non-flat strings. | 3943 // We need special handling for non-flat strings. |
3941 ASSERT_EQ(0, kSeqStringTag); | 3944 ASSERT_EQ(0, kSeqStringTag); |
3942 __ testb(temp.reg(), Immediate(kStringRepresentationMask)); | 3945 __ testb(temp.reg(), Immediate(kStringRepresentationMask)); |
3943 __ j(not_zero, ¬_a_flat_string); | 3946 __ j(not_zero, ¬_a_flat_string); |
3944 // Check for 1-byte or 2-byte string. | 3947 // Check for 1-byte or 2-byte string. |
3945 ASSERT_EQ(0, kTwoByteStringTag); | 3948 ASSERT_EQ(0, kTwoByteStringTag); |
3946 | |
3947 // Untag the index. | |
3948 __ SmiToInteger32(index.reg(), index.reg()); | |
3949 | |
3950 __ testb(temp.reg(), Immediate(kStringEncodingMask)); | 3949 __ testb(temp.reg(), Immediate(kStringEncodingMask)); |
3951 __ j(not_zero, &ascii_string); | 3950 __ j(not_zero, &ascii_string); |
3952 | 3951 |
3953 // 2-byte string. | 3952 // 2-byte string. |
3954 // Load the 2-byte character code into the temp register. | 3953 // Load the 2-byte character code into the temp register. |
3955 __ movzxwl(temp.reg(), FieldOperand(object.reg(), | 3954 __ movzxwl(temp.reg(), FieldOperand(object.reg(), |
3956 index.reg(), | 3955 index.reg(), |
3957 times_2, | 3956 times_2, |
3958 SeqTwoByteString::kHeaderSize)); | 3957 SeqTwoByteString::kHeaderSize)); |
3959 __ jmp(&got_char_code); | 3958 __ jmp(&got_char_code); |
(...skipping 1650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5610 | 5609 |
5611 is_string.Bind(&left_side); | 5610 is_string.Bind(&left_side); |
5612 // left_side is a sequential ASCII string. | 5611 // left_side is a sequential ASCII string. |
5613 ASSERT(left_side.reg().is(left_reg)); | 5612 ASSERT(left_side.reg().is(left_reg)); |
5614 right_side = Result(right_val); | 5613 right_side = Result(right_val); |
5615 Result temp2 = allocator_->Allocate(); | 5614 Result temp2 = allocator_->Allocate(); |
5616 ASSERT(temp2.is_valid()); | 5615 ASSERT(temp2.is_valid()); |
5617 // Test string equality and comparison. | 5616 // Test string equality and comparison. |
5618 if (cc == equal) { | 5617 if (cc == equal) { |
5619 Label comparison_done; | 5618 Label comparison_done; |
5620 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset), | 5619 __ cmpl(FieldOperand(left_side.reg(), String::kLengthOffset), |
5621 Smi::FromInt(1)); | 5620 Immediate(1)); |
5622 __ j(not_equal, &comparison_done); | 5621 __ j(not_equal, &comparison_done); |
5623 uint8_t char_value = | 5622 uint8_t char_value = |
5624 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 5623 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
5625 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), | 5624 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
5626 Immediate(char_value)); | 5625 Immediate(char_value)); |
5627 __ bind(&comparison_done); | 5626 __ bind(&comparison_done); |
5628 } else { | 5627 } else { |
5629 __ movq(temp2.reg(), | 5628 __ movl(temp2.reg(), |
5630 FieldOperand(left_side.reg(), String::kLengthOffset)); | 5629 FieldOperand(left_side.reg(), String::kLengthOffset)); |
5631 __ SmiSubConstant(temp2.reg(), temp2.reg(), Smi::FromInt(1)); | 5630 __ subl(temp2.reg(), Immediate(1)); |
5632 Label comparison; | 5631 Label comparison; |
5633 // If the length is 0 then the subtraction gave -1 which compares less | 5632 // If the length is 0 then the subtraction gave -1 which compares less |
5634 // than any character. | 5633 // than any character. |
5635 __ j(negative, &comparison); | 5634 __ j(negative, &comparison); |
5636 // Otherwise load the first character. | 5635 // Otherwise load the first character. |
5637 __ movzxbl(temp2.reg(), | 5636 __ movzxbl(temp2.reg(), |
5638 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); | 5637 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); |
5639 __ bind(&comparison); | 5638 __ bind(&comparison); |
5640 // Compare the first character of the string with the | 5639 // Compare the first character of the string with the |
5641 // constant 1-character string. | 5640 // constant 1-character string. |
5642 uint8_t char_value = | 5641 uint8_t char_value = |
5643 static_cast<uint8_t>(String::cast(*right_side.handle())->Get(0)); | 5642 static_cast<uint8_t>(String::cast(*right_side.handle())->Get(0)); |
5644 __ cmpb(temp2.reg(), Immediate(char_value)); | 5643 __ cmpb(temp2.reg(), Immediate(char_value)); |
5645 Label characters_were_different; | 5644 Label characters_were_different; |
5646 __ j(not_equal, &characters_were_different); | 5645 __ j(not_equal, &characters_were_different); |
5647 // If the first character is the same then the long string sorts after | 5646 // If the first character is the same then the long string sorts after |
5648 // the short one. | 5647 // the short one. |
5649 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset), | 5648 __ cmpl(FieldOperand(left_side.reg(), String::kLengthOffset), |
5650 Smi::FromInt(1)); | 5649 Immediate(1)); |
5651 __ bind(&characters_were_different); | 5650 __ bind(&characters_were_different); |
5652 } | 5651 } |
5653 temp2.Unuse(); | 5652 temp2.Unuse(); |
5654 left_side.Unuse(); | 5653 left_side.Unuse(); |
5655 right_side.Unuse(); | 5654 right_side.Unuse(); |
5656 dest->Split(cc); | 5655 dest->Split(cc); |
5657 } | 5656 } |
5658 } else { | 5657 } else { |
5659 // Neither side is a constant Smi, constant 1-char string, or constant null. | 5658 // Neither side is a constant Smi, constant 1-char string, or constant null. |
5660 // If either side is a non-smi constant, skip the smi check. | 5659 // If either side is a non-smi constant, skip the smi check. |
(...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7089 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); | 7088 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); |
7090 __ j(not_zero, &false_result); | 7089 __ j(not_zero, &false_result); |
7091 | 7090 |
7092 // JavaScript object => true. | 7091 // JavaScript object => true. |
7093 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); | 7092 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); |
7094 __ j(above_equal, &true_result); | 7093 __ j(above_equal, &true_result); |
7095 | 7094 |
7096 // String value => false iff empty. | 7095 // String value => false iff empty. |
7097 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); | 7096 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); |
7098 __ j(above_equal, ¬_string); | 7097 __ j(above_equal, ¬_string); |
7099 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); | 7098 __ movl(rdx, FieldOperand(rax, String::kLengthOffset)); |
7100 __ testq(rdx, rdx); | 7099 __ testl(rdx, rdx); |
7101 __ j(zero, &false_result); | 7100 __ j(zero, &false_result); |
7102 __ jmp(&true_result); | 7101 __ jmp(&true_result); |
7103 | 7102 |
7104 __ bind(¬_string); | 7103 __ bind(¬_string); |
7105 // HeapNumber => false iff +0, -0, or NaN. | 7104 // HeapNumber => false iff +0, -0, or NaN. |
7106 // These three cases set C3 when compared to zero in the FPU. | 7105 // These three cases set C3 when compared to zero in the FPU. |
7107 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); | 7106 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); |
7108 __ j(not_equal, &true_result); | 7107 __ j(not_equal, &true_result); |
7109 __ fldz(); // Load zero onto fp stack | 7108 __ fldz(); // Load zero onto fp stack |
7110 // Load heap-number double value onto fp stack | 7109 // Load heap-number double value onto fp stack |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7490 __ j(above, &runtime); | 7489 __ j(above, &runtime); |
7491 | 7490 |
7492 // rcx: RegExp data (FixedArray) | 7491 // rcx: RegExp data (FixedArray) |
7493 // rdx: Number of capture registers | 7492 // rdx: Number of capture registers |
7494 // Check that the second argument is a string. | 7493 // Check that the second argument is a string. |
7495 __ movq(rax, Operand(rsp, kSubjectOffset)); | 7494 __ movq(rax, Operand(rsp, kSubjectOffset)); |
7496 __ JumpIfSmi(rax, &runtime); | 7495 __ JumpIfSmi(rax, &runtime); |
7497 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); | 7496 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); |
7498 __ j(NegateCondition(is_string), &runtime); | 7497 __ j(NegateCondition(is_string), &runtime); |
7499 // Get the length of the string to rbx. | 7498 // Get the length of the string to rbx. |
7500 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 7499 __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); |
7501 | 7500 |
7502 // rbx: Length of subject string as smi | 7501 // rbx: Length of subject string |
7503 // rcx: RegExp data (FixedArray) | 7502 // rcx: RegExp data (FixedArray) |
7504 // rdx: Number of capture registers | 7503 // rdx: Number of capture registers |
7505 // Check that the third argument is a positive smi less than the string | 7504 // Check that the third argument is a positive smi less than the string |
7506 // length. A negative value will be greater (unsigned comparison). | 7505 // length. A negative value will be greater (unsigned comparison). |
7507 __ movq(rax, Operand(rsp, kPreviousIndexOffset)); | 7506 __ movq(rax, Operand(rsp, kPreviousIndexOffset)); |
7508 __ JumpIfNotSmi(rax, &runtime); | 7507 __ SmiToInteger32(rax, rax); |
7509 __ SmiCompare(rax, rbx); | 7508 __ cmpl(rax, rbx); |
7510 __ j(above_equal, &runtime); | 7509 __ j(above, &runtime); |
7511 | 7510 |
7512 // rcx: RegExp data (FixedArray) | 7511 // rcx: RegExp data (FixedArray) |
7513 // rdx: Number of capture registers | 7512 // rdx: Number of capture registers |
7514 // Check that the fourth object is a JSArray object. | 7513 // Check that the fourth object is a JSArray object. |
7515 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); | 7514 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); |
7516 __ JumpIfSmi(rax, &runtime); | 7515 __ JumpIfSmi(rax, &runtime); |
7517 __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister); | 7516 __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister); |
7518 __ j(not_equal, &runtime); | 7517 __ j(not_equal, &runtime); |
7519 // Check that the JSArray is in fast case. | 7518 // Check that the JSArray is in fast case. |
7520 __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); | 7519 __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7653 // Keep track on aliasing between argX defined above and the registers used. | 7652 // Keep track on aliasing between argX defined above and the registers used. |
7654 // rax: subject string | 7653 // rax: subject string |
7655 // rbx: previous index | 7654 // rbx: previous index |
7656 // rdi: encoding of subject string (1 if ascii 0 if two_byte); | 7655 // rdi: encoding of subject string (1 if ascii 0 if two_byte); |
7657 // r12: code | 7656 // r12: code |
7658 | 7657 |
7659 // Argument 4: End of string data | 7658 // Argument 4: End of string data |
7660 // Argument 3: Start of string data | 7659 // Argument 3: Start of string data |
7661 Label setup_two_byte, setup_rest; | 7660 Label setup_two_byte, setup_rest; |
7662 __ testb(rdi, rdi); | 7661 __ testb(rdi, rdi); |
7663 __ movq(rdi, FieldOperand(rax, String::kLengthOffset)); | 7662 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
7664 __ j(zero, &setup_two_byte); | 7663 __ j(zero, &setup_two_byte); |
7665 __ SmiToInteger32(rdi, rdi); | |
7666 __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize)); | 7664 __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize)); |
7667 __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize)); | 7665 __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize)); |
7668 __ jmp(&setup_rest); | 7666 __ jmp(&setup_rest); |
7669 __ bind(&setup_two_byte); | 7667 __ bind(&setup_two_byte); |
7670 __ SmiToInteger32(rdi, rdi); | |
7671 __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize)); | 7668 __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize)); |
7672 __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 7669 __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
7673 | 7670 |
7674 __ bind(&setup_rest); | 7671 __ bind(&setup_rest); |
7675 // Argument 2: Previous index. | 7672 // Argument 2: Previous index. |
7676 __ movq(arg2, rbx); | 7673 __ movq(arg2, rbx); |
7677 | 7674 |
7678 // Argument 1: Subject string. | 7675 // Argument 1: Subject string. |
7679 __ movq(arg1, rax); | 7676 __ movq(arg1, rax); |
7680 | 7677 |
(...skipping 2139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9820 __ j(is_smi, &string_add_runtime); | 9817 __ j(is_smi, &string_add_runtime); |
9821 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 9818 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
9822 __ j(above_equal, &string_add_runtime); | 9819 __ j(above_equal, &string_add_runtime); |
9823 } | 9820 } |
9824 | 9821 |
9825 // Both arguments are strings. | 9822 // Both arguments are strings. |
9826 // rax: first string | 9823 // rax: first string |
9827 // rdx: second string | 9824 // rdx: second string |
9828 // Check if either of the strings are empty. In that case return the other. | 9825 // Check if either of the strings are empty. In that case return the other. |
9829 Label second_not_zero_length, both_not_zero_length; | 9826 Label second_not_zero_length, both_not_zero_length; |
9830 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 9827 __ movl(rcx, FieldOperand(rdx, String::kLengthOffset)); |
9831 __ SmiTest(rcx); | 9828 __ testl(rcx, rcx); |
9832 __ j(not_zero, &second_not_zero_length); | 9829 __ j(not_zero, &second_not_zero_length); |
9833 // Second string is empty, result is first string which is already in rax. | 9830 // Second string is empty, result is first string which is already in rax. |
9834 __ IncrementCounter(&Counters::string_add_native, 1); | 9831 __ IncrementCounter(&Counters::string_add_native, 1); |
9835 __ ret(2 * kPointerSize); | 9832 __ ret(2 * kPointerSize); |
9836 __ bind(&second_not_zero_length); | 9833 __ bind(&second_not_zero_length); |
9837 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 9834 __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); |
9838 __ SmiTest(rbx); | 9835 __ testl(rbx, rbx); |
9839 __ j(not_zero, &both_not_zero_length); | 9836 __ j(not_zero, &both_not_zero_length); |
9840 // First string is empty, result is second string which is in rdx. | 9837 // First string is empty, result is second string which is in rdx. |
9841 __ movq(rax, rdx); | 9838 __ movq(rax, rdx); |
9842 __ IncrementCounter(&Counters::string_add_native, 1); | 9839 __ IncrementCounter(&Counters::string_add_native, 1); |
9843 __ ret(2 * kPointerSize); | 9840 __ ret(2 * kPointerSize); |
9844 | 9841 |
9845 // Both strings are non-empty. | 9842 // Both strings are non-empty. |
9846 // rax: first string | 9843 // rax: first string |
9847 // rbx: length of first string | 9844 // rbx: length of first string |
9848 // rcx: length of second string | 9845 // rcx: length of second string |
9849 // rdx: second string | 9846 // rdx: second string |
9850 // r8: map of first string if string check was performed above | 9847 // r8: map of first string if string check was performed above |
9851 // r9: map of second string if string check was performed above | 9848 // r9: map of second string if string check was performed above |
9852 Label string_add_flat_result, longer_than_two; | 9849 Label string_add_flat_result, longer_than_two; |
9853 __ bind(&both_not_zero_length); | 9850 __ bind(&both_not_zero_length); |
9854 | 9851 |
9855 // If arguments where known to be strings, maps are not loaded to r8 and r9 | 9852 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
9856 // by the code above. | 9853 // by the code above. |
9857 if (!string_check_) { | 9854 if (!string_check_) { |
9858 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 9855 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
9859 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 9856 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
9860 } | 9857 } |
9861 // Get the instance types of the two strings as they will be needed soon. | 9858 // Get the instance types of the two strings as they will be needed soon. |
9862 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 9859 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
9863 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 9860 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
9864 | 9861 |
9865 // Look at the length of the result of adding the two strings. | 9862 // Look at the length of the result of adding the two strings. |
9866 ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 9863 __ addl(rbx, rcx); |
9867 __ SmiAdd(rbx, rbx, rcx, NULL); | |
9868 // Use the runtime system when adding two one character strings, as it | 9864 // Use the runtime system when adding two one character strings, as it |
9869 // contains optimizations for this specific case using the symbol table. | 9865 // contains optimizations for this specific case using the symbol table. |
9870 __ SmiCompare(rbx, Smi::FromInt(2)); | 9866 __ cmpl(rbx, Immediate(2)); |
9871 __ j(not_equal, &longer_than_two); | 9867 __ j(not_equal, &longer_than_two); |
9872 | 9868 |
9873 // Check that both strings are non-external ascii strings. | 9869 // Check that both strings are non-external ascii strings. |
9874 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, | 9870 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, |
9875 &string_add_runtime); | 9871 &string_add_runtime); |
9876 | 9872 |
9877 // Get the two characters forming the sub string. | 9873 // Get the two characters forming the sub string. |
9878 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); | 9874 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
9879 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); | 9875 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
9880 | 9876 |
9881 // Try to lookup two character string in symbol table. If it is not found | 9877 // Try to lookup two character string in symbol table. If it is not found |
9882 // just allocate a new one. | 9878 // just allocate a new one. |
9883 Label make_two_character_string, make_flat_ascii_string; | 9879 Label make_two_character_string, make_flat_ascii_string; |
9884 GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15, | 9880 GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15, |
9885 &make_two_character_string); | 9881 &make_two_character_string); |
9886 __ IncrementCounter(&Counters::string_add_native, 1); | 9882 __ IncrementCounter(&Counters::string_add_native, 1); |
9887 __ ret(2 * kPointerSize); | 9883 __ ret(2 * kPointerSize); |
9888 | 9884 |
9889 __ bind(&make_two_character_string); | 9885 __ bind(&make_two_character_string); |
9890 __ Set(rbx, 2); | 9886 __ Set(rbx, 2); |
9891 __ jmp(&make_flat_ascii_string); | 9887 __ jmp(&make_flat_ascii_string); |
9892 | 9888 |
9893 __ bind(&longer_than_two); | 9889 __ bind(&longer_than_two); |
9894 // Check if resulting string will be flat. | 9890 // Check if resulting string will be flat. |
9895 __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); | 9891 __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); |
9896 __ j(below, &string_add_flat_result); | 9892 __ j(below, &string_add_flat_result); |
9897 // Handle exceptionally long strings in the runtime system. | 9893 // Handle exceptionally long strings in the runtime system. |
9898 ASSERT((String::kMaxLength & 0x80000000) == 0); | 9894 ASSERT((String::kMaxLength & 0x80000000) == 0); |
9899 __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); | 9895 __ cmpl(rbx, Immediate(String::kMaxLength)); |
9900 __ j(above, &string_add_runtime); | 9896 __ j(above, &string_add_runtime); |
9901 | 9897 |
9902 // If result is not supposed to be flat, allocate a cons string object. If | 9898 // If result is not supposed to be flat, allocate a cons string object. If |
9903 // both strings are ascii the result is an ascii cons string. | 9899 // both strings are ascii the result is an ascii cons string. |
9904 // rax: first string | 9900 // rax: first string |
9905 // ebx: length of resulting flat string | 9901 // ebx: length of resulting flat string |
9906 // rdx: second string | 9902 // rdx: second string |
9907 // r8: instance type of first string | 9903 // r8: instance type of first string |
9908 // r9: instance type of second string | 9904 // r9: instance type of second string |
9909 Label non_ascii, allocated; | 9905 Label non_ascii, allocated; |
9910 __ movl(rcx, r8); | 9906 __ movl(rcx, r8); |
9911 __ and_(rcx, r9); | 9907 __ and_(rcx, r9); |
9912 ASSERT(kStringEncodingMask == kAsciiStringTag); | 9908 ASSERT(kStringEncodingMask == kAsciiStringTag); |
9913 __ testl(rcx, Immediate(kAsciiStringTag)); | 9909 __ testl(rcx, Immediate(kAsciiStringTag)); |
9914 __ j(zero, &non_ascii); | 9910 __ j(zero, &non_ascii); |
9915 // Allocate an acsii cons string. | 9911 // Allocate an acsii cons string. |
9916 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); | 9912 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); |
9917 __ bind(&allocated); | 9913 __ bind(&allocated); |
9918 // Fill the fields of the cons string. | 9914 // Fill the fields of the cons string. |
9919 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); | 9915 __ movl(FieldOperand(rcx, ConsString::kLengthOffset), rbx); |
9920 __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset), | 9916 __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset), |
9921 Immediate(String::kEmptyHashField)); | 9917 Immediate(String::kEmptyHashField)); |
9922 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); | 9918 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); |
9923 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | 9919 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); |
9924 __ movq(rax, rcx); | 9920 __ movq(rax, rcx); |
9925 __ IncrementCounter(&Counters::string_add_native, 1); | 9921 __ IncrementCounter(&Counters::string_add_native, 1); |
9926 __ ret(2 * kPointerSize); | 9922 __ ret(2 * kPointerSize); |
9927 __ bind(&non_ascii); | 9923 __ bind(&non_ascii); |
9928 // Allocate a two byte cons string. | 9924 // Allocate a two byte cons string. |
9929 __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); | 9925 __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); |
9930 __ jmp(&allocated); | 9926 __ jmp(&allocated); |
9931 | 9927 |
9932 // Handle creating a flat result. First check that both strings are not | 9928 // Handle creating a flat result. First check that both strings are not |
9933 // external strings. | 9929 // external strings. |
9934 // rax: first string | 9930 // rax: first string |
9935 // ebx: length of resulting flat string as smi | 9931 // ebx: length of resulting flat string |
9936 // rdx: second string | 9932 // rdx: second string |
9937 // r8: instance type of first string | 9933 // r8: instance type of first string |
9938 // r9: instance type of first string | 9934 // r9: instance type of first string |
9939 __ bind(&string_add_flat_result); | 9935 __ bind(&string_add_flat_result); |
9940 __ SmiToInteger32(rbx, rbx); | |
9941 __ movl(rcx, r8); | 9936 __ movl(rcx, r8); |
9942 __ and_(rcx, Immediate(kStringRepresentationMask)); | 9937 __ and_(rcx, Immediate(kStringRepresentationMask)); |
9943 __ cmpl(rcx, Immediate(kExternalStringTag)); | 9938 __ cmpl(rcx, Immediate(kExternalStringTag)); |
9944 __ j(equal, &string_add_runtime); | 9939 __ j(equal, &string_add_runtime); |
9945 __ movl(rcx, r9); | 9940 __ movl(rcx, r9); |
9946 __ and_(rcx, Immediate(kStringRepresentationMask)); | 9941 __ and_(rcx, Immediate(kStringRepresentationMask)); |
9947 __ cmpl(rcx, Immediate(kExternalStringTag)); | 9942 __ cmpl(rcx, Immediate(kExternalStringTag)); |
9948 __ j(equal, &string_add_runtime); | 9943 __ j(equal, &string_add_runtime); |
9949 // Now check if both strings are ascii strings. | 9944 // Now check if both strings are ascii strings. |
9950 // rax: first string | 9945 // rax: first string |
9951 // ebx: length of resulting flat string | 9946 // ebx: length of resulting flat string |
9952 // rdx: second string | 9947 // rdx: second string |
9953 // r8: instance type of first string | 9948 // r8: instance type of first string |
9954 // r9: instance type of second string | 9949 // r9: instance type of second string |
9955 Label non_ascii_string_add_flat_result; | 9950 Label non_ascii_string_add_flat_result; |
9956 ASSERT(kStringEncodingMask == kAsciiStringTag); | 9951 ASSERT(kStringEncodingMask == kAsciiStringTag); |
9957 __ testl(r8, Immediate(kAsciiStringTag)); | 9952 __ testl(r8, Immediate(kAsciiStringTag)); |
9958 __ j(zero, &non_ascii_string_add_flat_result); | 9953 __ j(zero, &non_ascii_string_add_flat_result); |
9959 __ testl(r9, Immediate(kAsciiStringTag)); | 9954 __ testl(r9, Immediate(kAsciiStringTag)); |
9960 __ j(zero, &string_add_runtime); | 9955 __ j(zero, &string_add_runtime); |
9961 | 9956 |
9962 __ bind(&make_flat_ascii_string); | 9957 __ bind(&make_flat_ascii_string); |
9963 // Both strings are ascii strings. As they are short they are both flat. | 9958 // Both strings are ascii strings. As they are short they are both flat. |
9964 __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); | 9959 __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
9965 // rcx: result string | 9960 // rcx: result string |
9966 __ movq(rbx, rcx); | 9961 __ movq(rbx, rcx); |
9967 // Locate first character of result. | 9962 // Locate first character of result. |
9968 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9963 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
9969 // Locate first character of first argument | 9964 // Locate first character of first argument |
9970 __ movq(rdi, FieldOperand(rax, String::kLengthOffset)); | 9965 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
9971 __ SmiToInteger32(rdi, rdi); | |
9972 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9966 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
9973 // rax: first char of first argument | 9967 // rax: first char of first argument |
9974 // rbx: result string | 9968 // rbx: result string |
9975 // rcx: first character of result | 9969 // rcx: first character of result |
9976 // rdx: second string | 9970 // rdx: second string |
9977 // rdi: length of first argument | 9971 // rdi: length of first argument |
9978 GenerateCopyCharacters(masm, rcx, rax, rdi, true); | 9972 GenerateCopyCharacters(masm, rcx, rax, rdi, true); |
9979 // Locate first character of second argument. | 9973 // Locate first character of second argument. |
9980 __ movq(rdi, FieldOperand(rdx, String::kLengthOffset)); | 9974 __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
9981 __ SmiToInteger32(rdi, rdi); | |
9982 __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9975 __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
9983 // rbx: result string | 9976 // rbx: result string |
9984 // rcx: next character of result | 9977 // rcx: next character of result |
9985 // rdx: first char of second argument | 9978 // rdx: first char of second argument |
9986 // rdi: length of second argument | 9979 // rdi: length of second argument |
9987 GenerateCopyCharacters(masm, rcx, rdx, rdi, true); | 9980 GenerateCopyCharacters(masm, rcx, rdx, rdi, true); |
9988 __ movq(rax, rbx); | 9981 __ movq(rax, rbx); |
9989 __ IncrementCounter(&Counters::string_add_native, 1); | 9982 __ IncrementCounter(&Counters::string_add_native, 1); |
9990 __ ret(2 * kPointerSize); | 9983 __ ret(2 * kPointerSize); |
9991 | 9984 |
9992 // Handle creating a flat two byte result. | 9985 // Handle creating a flat two byte result. |
9993 // rax: first string - known to be two byte | 9986 // rax: first string - known to be two byte |
9994 // rbx: length of resulting flat string | 9987 // rbx: length of resulting flat string |
9995 // rdx: second string | 9988 // rdx: second string |
9996 // r8: instance type of first string | 9989 // r8: instance type of first string |
9997 // r9: instance type of first string | 9990 // r9: instance type of first string |
9998 __ bind(&non_ascii_string_add_flat_result); | 9991 __ bind(&non_ascii_string_add_flat_result); |
9999 __ and_(r9, Immediate(kAsciiStringTag)); | 9992 __ and_(r9, Immediate(kAsciiStringTag)); |
10000 __ j(not_zero, &string_add_runtime); | 9993 __ j(not_zero, &string_add_runtime); |
10001 // Both strings are two byte strings. As they are short they are both | 9994 // Both strings are two byte strings. As they are short they are both |
10002 // flat. | 9995 // flat. |
10003 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r15, &string_add_runtime); | 9996 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
10004 // rcx: result string | 9997 // rcx: result string |
10005 __ movq(rbx, rcx); | 9998 __ movq(rbx, rcx); |
10006 // Locate first character of result. | 9999 // Locate first character of result. |
10007 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 10000 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
10008 // Locate first character of first argument. | 10001 // Locate first character of first argument. |
10009 __ movq(rdi, FieldOperand(rax, String::kLengthOffset)); | 10002 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
10010 __ SmiToInteger32(rdi, rdi); | |
10011 __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 10003 __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
10012 // rax: first char of first argument | 10004 // rax: first char of first argument |
10013 // rbx: result string | 10005 // rbx: result string |
10014 // rcx: first character of result | 10006 // rcx: first character of result |
10015 // rdx: second argument | 10007 // rdx: second argument |
10016 // rdi: length of first argument | 10008 // rdi: length of first argument |
10017 GenerateCopyCharacters(masm, rcx, rax, rdi, false); | 10009 GenerateCopyCharacters(masm, rcx, rax, rdi, false); |
10018 // Locate first character of second argument. | 10010 // Locate first character of second argument. |
10019 __ movq(rdi, FieldOperand(rdx, String::kLengthOffset)); | 10011 __ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
10020 __ SmiToInteger32(rdi, rdi); | |
10021 __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 10012 __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
10022 // rbx: result string | 10013 // rbx: result string |
10023 // rcx: next character of result | 10014 // rcx: next character of result |
10024 // rdx: first char of second argument | 10015 // rdx: first char of second argument |
10025 // rdi: length of second argument | 10016 // rdi: length of second argument |
10026 GenerateCopyCharacters(masm, rcx, rdx, rdi, false); | 10017 GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
10027 __ movq(rax, rbx); | 10018 __ movq(rax, rbx); |
10028 __ IncrementCounter(&Counters::string_add_native, 1); | 10019 __ IncrementCounter(&Counters::string_add_native, 1); |
10029 __ ret(2 * kPointerSize); | 10020 __ ret(2 * kPointerSize); |
10030 | 10021 |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10192 FieldOperand(symbol_table, | 10183 FieldOperand(symbol_table, |
10193 scratch, | 10184 scratch, |
10194 times_pointer_size, | 10185 times_pointer_size, |
10195 SymbolTable::kElementsStartOffset)); | 10186 SymbolTable::kElementsStartOffset)); |
10196 | 10187 |
10197 // If entry is undefined no string with this hash can be found. | 10188 // If entry is undefined no string with this hash can be found. |
10198 __ cmpq(candidate, undefined); | 10189 __ cmpq(candidate, undefined); |
10199 __ j(equal, not_found); | 10190 __ j(equal, not_found); |
10200 | 10191 |
10201 // If length is not 2 the string is not a candidate. | 10192 // If length is not 2 the string is not a candidate. |
10202 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | 10193 __ cmpl(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); |
10203 Smi::FromInt(2)); | |
10204 __ j(not_equal, &next_probe[i]); | 10194 __ j(not_equal, &next_probe[i]); |
10205 | 10195 |
10206 // We use kScratchRegister as a temporary register in assumption that | 10196 // We use kScratchRegister as a temporary register in assumption that |
10207 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly | 10197 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly |
10208 Register temp = kScratchRegister; | 10198 Register temp = kScratchRegister; |
10209 | 10199 |
10210 // Check that the candidate is a non-external ascii string. | 10200 // Check that the candidate is a non-external ascii string. |
10211 __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | 10201 __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset)); |
10212 __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 10202 __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |
10213 __ JumpIfInstanceTypeIsNotSequentialAscii( | 10203 __ JumpIfInstanceTypeIsNotSequentialAscii( |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10437 Register right, | 10427 Register right, |
10438 Register scratch1, | 10428 Register scratch1, |
10439 Register scratch2, | 10429 Register scratch2, |
10440 Register scratch3, | 10430 Register scratch3, |
10441 Register scratch4) { | 10431 Register scratch4) { |
10442 // Ensure that you can always subtract a string length from a non-negative | 10432 // Ensure that you can always subtract a string length from a non-negative |
10443 // number (e.g. another length). | 10433 // number (e.g. another length). |
10444 ASSERT(String::kMaxLength < 0x7fffffff); | 10434 ASSERT(String::kMaxLength < 0x7fffffff); |
10445 | 10435 |
10446 // Find minimum length and length difference. | 10436 // Find minimum length and length difference. |
10447 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); | 10437 __ movl(scratch1, FieldOperand(left, String::kLengthOffset)); |
10448 __ movq(scratch4, scratch1); | 10438 __ movl(scratch4, scratch1); |
10449 __ SmiSub(scratch4, | 10439 __ subl(scratch4, FieldOperand(right, String::kLengthOffset)); |
10450 scratch4, | |
10451 FieldOperand(right, String::kLengthOffset), | |
10452 NULL); | |
10453 // Register scratch4 now holds left.length - right.length. | 10440 // Register scratch4 now holds left.length - right.length. |
10454 const Register length_difference = scratch4; | 10441 const Register length_difference = scratch4; |
10455 Label left_shorter; | 10442 Label left_shorter; |
10456 __ j(less, &left_shorter); | 10443 __ j(less, &left_shorter); |
10457 // The right string isn't longer that the left one. | 10444 // The right string isn't longer that the left one. |
10458 // Get the right string's length by subtracting the (non-negative) difference | 10445 // Get the right string's length by subtracting the (non-negative) difference |
10459 // from the left string's length. | 10446 // from the left string's length. |
10460 __ SmiSub(scratch1, scratch1, length_difference, NULL); | 10447 __ subl(scratch1, length_difference); |
10461 __ bind(&left_shorter); | 10448 __ bind(&left_shorter); |
10462 // Register scratch1 now holds Min(left.length, right.length). | 10449 // Register scratch1 now holds Min(left.length, right.length). |
10463 const Register min_length = scratch1; | 10450 const Register min_length = scratch1; |
10464 | 10451 |
10465 Label compare_lengths; | 10452 Label compare_lengths; |
10466 // If min-length is zero, go directly to comparing lengths. | 10453 // If min-length is zero, go directly to comparing lengths. |
10467 __ SmiTest(min_length); | 10454 __ testl(min_length, min_length); |
10468 __ j(zero, &compare_lengths); | 10455 __ j(zero, &compare_lengths); |
10469 | 10456 |
10470 __ SmiToInteger32(min_length, min_length); | |
10471 | |
10472 // Registers scratch2 and scratch3 are free. | 10457 // Registers scratch2 and scratch3 are free. |
10473 Label result_not_equal; | 10458 Label result_not_equal; |
10474 Label loop; | 10459 Label loop; |
10475 { | 10460 { |
10476 // Check characters 0 .. min_length - 1 in a loop. | 10461 // Check characters 0 .. min_length - 1 in a loop. |
10477 // Use scratch3 as loop index, min_length as limit and scratch2 | 10462 // Use scratch3 as loop index, min_length as limit and scratch2 |
10478 // for computation. | 10463 // for computation. |
10479 const Register index = scratch3; | 10464 const Register index = scratch3; |
10480 __ movl(index, Immediate(0)); // Index into strings. | 10465 __ movl(index, Immediate(0)); // Index into strings. |
10481 __ bind(&loop); | 10466 __ bind(&loop); |
(...skipping 10 matching lines...) Expand all Loading... |
10492 index, | 10477 index, |
10493 times_1, | 10478 times_1, |
10494 SeqAsciiString::kHeaderSize - 1)); | 10479 SeqAsciiString::kHeaderSize - 1)); |
10495 __ j(not_equal, &result_not_equal); | 10480 __ j(not_equal, &result_not_equal); |
10496 __ cmpl(index, min_length); | 10481 __ cmpl(index, min_length); |
10497 __ j(not_equal, &loop); | 10482 __ j(not_equal, &loop); |
10498 } | 10483 } |
10499 // Completed loop without finding different characters. | 10484 // Completed loop without finding different characters. |
10500 // Compare lengths (precomputed). | 10485 // Compare lengths (precomputed). |
10501 __ bind(&compare_lengths); | 10486 __ bind(&compare_lengths); |
10502 __ SmiTest(length_difference); | 10487 __ testl(length_difference, length_difference); |
10503 __ j(not_zero, &result_not_equal); | 10488 __ j(not_zero, &result_not_equal); |
10504 | 10489 |
10505 // Result is EQUAL. | 10490 // Result is EQUAL. |
10506 __ Move(rax, Smi::FromInt(EQUAL)); | 10491 __ Move(rax, Smi::FromInt(EQUAL)); |
10507 __ ret(2 * kPointerSize); | 10492 __ ret(2 * kPointerSize); |
10508 | 10493 |
10509 Label result_greater; | 10494 Label result_greater; |
10510 __ bind(&result_not_equal); | 10495 __ bind(&result_not_equal); |
10511 // Unequal comparison of left to right, either character or length. | 10496 // Unequal comparison of left to right, either character or length. |
10512 __ j(greater, &result_greater); | 10497 __ j(greater, &result_greater); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10646 // Call the function from C++. | 10631 // Call the function from C++. |
10647 return FUNCTION_CAST<ModuloFunction>(buffer); | 10632 return FUNCTION_CAST<ModuloFunction>(buffer); |
10648 } | 10633 } |
10649 | 10634 |
10650 #endif | 10635 #endif |
10651 | 10636 |
10652 | 10637 |
10653 #undef __ | 10638 #undef __ |
10654 | 10639 |
10655 } } // namespace v8::internal | 10640 } } // namespace v8::internal |
OLD | NEW |