| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 2373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2384 // Ensure that a RegExp stack is allocated. | 2384 // Ensure that a RegExp stack is allocated. |
| 2385 Isolate* isolate = masm->isolate(); | 2385 Isolate* isolate = masm->isolate(); |
| 2386 ExternalReference address_of_regexp_stack_memory_address = | 2386 ExternalReference address_of_regexp_stack_memory_address = |
| 2387 ExternalReference::address_of_regexp_stack_memory_address(isolate); | 2387 ExternalReference::address_of_regexp_stack_memory_address(isolate); |
| 2388 ExternalReference address_of_regexp_stack_memory_size = | 2388 ExternalReference address_of_regexp_stack_memory_size = |
| 2389 ExternalReference::address_of_regexp_stack_memory_size(isolate); | 2389 ExternalReference::address_of_regexp_stack_memory_size(isolate); |
| 2390 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); | 2390 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); |
| 2391 __ testq(kScratchRegister, kScratchRegister); | 2391 __ testq(kScratchRegister, kScratchRegister); |
| 2392 __ j(zero, &runtime); | 2392 __ j(zero, &runtime); |
| 2393 | 2393 |
| 2394 | |
| 2395 // Check that the first argument is a JSRegExp object. | 2394 // Check that the first argument is a JSRegExp object. |
| 2396 __ movq(rax, Operand(rsp, kJSRegExpOffset)); | 2395 __ movq(rax, Operand(rsp, kJSRegExpOffset)); |
| 2397 __ JumpIfSmi(rax, &runtime); | 2396 __ JumpIfSmi(rax, &runtime); |
| 2398 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); | 2397 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); |
| 2399 __ j(not_equal, &runtime); | 2398 __ j(not_equal, &runtime); |
| 2400 // Check that the RegExp has been compiled (data contains a fixed array). | 2399 // Check that the RegExp has been compiled (data contains a fixed array). |
| 2401 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); | 2400 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 2402 if (FLAG_debug_code) { | 2401 if (FLAG_debug_code) { |
| 2403 Condition is_smi = masm->CheckSmi(rax); | 2402 Condition is_smi = masm->CheckSmi(rax); |
| 2404 __ Check(NegateCondition(is_smi), | 2403 __ Check(NegateCondition(is_smi), |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2455 Heap::kFixedArrayMapRootIndex); | 2454 Heap::kFixedArrayMapRootIndex); |
| 2456 __ j(not_equal, &runtime); | 2455 __ j(not_equal, &runtime); |
| 2457 // Check that the last match info has space for the capture registers and the | 2456 // Check that the last match info has space for the capture registers and the |
| 2458 // additional information. Ensure no overflow in add. | 2457 // additional information. Ensure no overflow in add. |
| 2459 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 2458 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 2460 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); | 2459 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 2461 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); | 2460 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 2462 __ cmpl(rdx, rdi); | 2461 __ cmpl(rdx, rdi); |
| 2463 __ j(greater, &runtime); | 2462 __ j(greater, &runtime); |
| 2464 | 2463 |
| 2464 // Reset offset for possibly sliced string. |
| 2465 __ Set(r14, 0); |
| 2465 // rax: RegExp data (FixedArray) | 2466 // rax: RegExp data (FixedArray) |
| 2466 // Check the representation and encoding of the subject string. | 2467 // Check the representation and encoding of the subject string. |
| 2467 Label seq_ascii_string, seq_two_byte_string, check_code; | 2468 Label seq_ascii_string, seq_two_byte_string, check_code; |
| 2468 __ movq(rdi, Operand(rsp, kSubjectOffset)); | 2469 __ movq(rdi, Operand(rsp, kSubjectOffset)); |
| 2470 // Make a copy of the original subject string. |
| 2471 __ movq(r15, rdi); |
| 2469 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2472 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 2470 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2473 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2471 // First check for flat two byte string. | 2474 // First check for flat two byte string. |
| 2472 __ andb(rbx, Immediate( | 2475 __ andb(rbx, Immediate( |
| 2473 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); | 2476 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); |
| 2474 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 2477 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
| 2475 __ j(zero, &seq_two_byte_string, Label::kNear); | 2478 __ j(zero, &seq_two_byte_string, Label::kNear); |
| 2476 // Any other flat string must be a flat ascii string. | 2479 // Any other flat string must be a flat ascii string. |
| 2477 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); | 2480 __ andb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); |
| 2478 __ j(zero, &seq_ascii_string, Label::kNear); | 2481 __ j(zero, &seq_ascii_string, Label::kNear); |
| 2479 | 2482 |
| 2480 // Check for flat cons string. | 2483 // Check for flat cons string or sliced string. |
| 2481 // A flat cons string is a cons string where the second part is the empty | 2484 // A flat cons string is a cons string where the second part is the empty |
| 2482 // string. In that case the subject string is just the first part of the cons | 2485 // string. In that case the subject string is just the first part of the cons |
| 2483 // string. Also in this case the first part of the cons string is known to be | 2486 // string. Also in this case the first part of the cons string is known to be |
| 2484 // a sequential string or an external string. | 2487 // a sequential string or an external string. |
| 2485 STATIC_ASSERT(kExternalStringTag !=0); | 2488 // In the case of a sliced string its offset has to be taken into account. |
| 2486 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); | 2489 Label cons_string, check_encoding; |
| 2487 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); | 2490 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 2488 __ j(not_zero, &runtime); | 2491 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 2489 // String is a cons string. | 2492 __ cmpq(rbx, Immediate(kExternalStringTag)); |
| 2493 __ j(less, &cons_string, Label::kNear); |
| 2494 __ j(equal, &runtime); |
| 2495 |
| 2496 // String is sliced. |
| 2497 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); |
| 2498 __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); |
| 2499 // r14: slice offset |
| 2500 // r15: original subject string |
| 2501 // rdi: parent string |
| 2502 __ jmp(&check_encoding, Label::kNear); |
| 2503 // String is a cons string, check whether it is flat. |
| 2504 __ bind(&cons_string); |
| 2490 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | 2505 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
| 2491 Heap::kEmptyStringRootIndex); | 2506 Heap::kEmptyStringRootIndex); |
| 2492 __ j(not_equal, &runtime); | 2507 __ j(not_equal, &runtime); |
| 2493 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | 2508 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
| 2509 // rdi: first part of cons string or parent of sliced string. |
| 2510 // rbx: map of first part of cons string or map of parent of sliced string. |
| 2511 // Is first part of cons or parent of slice a flat two byte string? |
| 2512 __ bind(&check_encoding); |
| 2494 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2513 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 2495 // String is a cons string with empty second part. | |
| 2496 // rdi: first part of cons string. | |
| 2497 // rbx: map of first part of cons string. | |
| 2498 // Is first part a flat two byte string? | |
| 2499 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2514 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
| 2500 Immediate(kStringRepresentationMask | kStringEncodingMask)); | 2515 Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 2501 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 2516 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
| 2502 __ j(zero, &seq_two_byte_string, Label::kNear); | 2517 __ j(zero, &seq_two_byte_string, Label::kNear); |
| 2503 // Any other flat string must be ascii. | 2518 // Any other flat string must be ascii. |
| 2504 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2519 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
| 2505 Immediate(kStringRepresentationMask)); | 2520 Immediate(kStringRepresentationMask)); |
| 2506 __ j(not_zero, &runtime); | 2521 __ j(not_zero, &runtime); |
| 2507 | 2522 |
| 2508 __ bind(&seq_ascii_string); | 2523 __ bind(&seq_ascii_string); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2585 Register arg3 = rdx; | 2600 Register arg3 = rdx; |
| 2586 Register arg2 = rsi; | 2601 Register arg2 = rsi; |
| 2587 Register arg1 = rdi; | 2602 Register arg1 = rdi; |
| 2588 #endif | 2603 #endif |
| 2589 | 2604 |
| 2590 // Keep track on aliasing between argX defined above and the registers used. | 2605 // Keep track on aliasing between argX defined above and the registers used. |
| 2591 // rdi: subject string | 2606 // rdi: subject string |
| 2592 // rbx: previous index | 2607 // rbx: previous index |
| 2593 // rcx: encoding of subject string (1 if ascii 0 if two_byte); | 2608 // rcx: encoding of subject string (1 if ascii 0 if two_byte); |
| 2594 // r11: code | 2609 // r11: code |
| 2610 // r14: slice offset |
| 2611 // r15: original subject string |
| 2612 |
| 2613 // Argument 2: Previous index. |
| 2614 __ movq(arg2, rbx); |
| 2595 | 2615 |
| 2596 // Argument 4: End of string data | 2616 // Argument 4: End of string data |
| 2597 // Argument 3: Start of string data | 2617 // Argument 3: Start of string data |
| 2598 Label setup_two_byte, setup_rest; | 2618 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; |
| 2619 // Prepare start and end index of the input. |
| 2620 // Load the length from the original sliced string if that is the case. |
| 2621 __ addq(rbx, r14); |
| 2622 __ SmiToInteger32(arg3, FieldOperand(r15, String::kLengthOffset)); |
| 2623 __ addq(r14, arg3); // Using arg3 as scratch. |
| 2624 |
| 2625 // rbx: start index of the input |
| 2626 // r14: end index of the input |
| 2627 // r15: original subject string |
| 2599 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. | 2628 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. |
| 2600 __ j(zero, &setup_two_byte, Label::kNear); | 2629 __ j(zero, &setup_two_byte, Label::kNear); |
| 2601 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2630 __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqAsciiString::kHeaderSize)); |
| 2602 __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize)); | |
| 2603 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); | 2631 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); |
| 2604 __ jmp(&setup_rest, Label::kNear); | 2632 __ jmp(&setup_rest, Label::kNear); |
| 2605 __ bind(&setup_two_byte); | 2633 __ bind(&setup_two_byte); |
| 2606 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2634 __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); |
| 2607 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); | |
| 2608 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 2635 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
| 2636 __ bind(&setup_rest); |
| 2609 | 2637 |
| 2610 __ bind(&setup_rest); | 2638 // Argument 1: Original subject string. |
| 2611 // Argument 2: Previous index. | 2639 // The original subject is in the previous stack frame. Therefore we have to |
| 2612 __ movq(arg2, rbx); | 2640 // use rbp, which points exactly to one pointer size below the previous rsp. |
| 2613 | 2641 // (Because creating a new stack frame pushes the previous rbp onto the stack |
| 2614 // Argument 1: Subject string. | 2642 // and thereby moves up rsp by one kPointerSize.) |
| 2615 #ifdef _WIN64 | 2643 __ movq(arg1, r15); |
| 2616 __ movq(arg1, rdi); | |
| 2617 #else | |
| 2618 // Already there in AMD64 calling convention. | |
| 2619 ASSERT(arg1.is(rdi)); | |
| 2620 USE(arg1); | |
| 2621 #endif | |
| 2622 | 2644 |
| 2623 // Locate the code entry and call it. | 2645 // Locate the code entry and call it. |
| 2624 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 2646 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 2625 __ call(r11); | 2647 __ call(r11); |
| 2626 | 2648 |
| 2627 __ LeaveApiExitFrame(); | 2649 __ LeaveApiExitFrame(); |
| 2628 | 2650 |
| 2629 // Check the result. | 2651 // Check the result. |
| 2630 Label success; | 2652 Label success; |
| 2631 Label exception; | 2653 Label exception; |
| (...skipping 1240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3872 } | 3894 } |
| 3873 | 3895 |
| 3874 | 3896 |
| 3875 // ------------------------------------------------------------------------- | 3897 // ------------------------------------------------------------------------- |
| 3876 // StringCharCodeAtGenerator | 3898 // StringCharCodeAtGenerator |
| 3877 | 3899 |
| 3878 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3900 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 3879 Label flat_string; | 3901 Label flat_string; |
| 3880 Label ascii_string; | 3902 Label ascii_string; |
| 3881 Label got_char_code; | 3903 Label got_char_code; |
| 3904 Label sliced_string; |
| 3882 | 3905 |
| 3883 // If the receiver is a smi trigger the non-string case. | 3906 // If the receiver is a smi trigger the non-string case. |
| 3884 __ JumpIfSmi(object_, receiver_not_string_); | 3907 __ JumpIfSmi(object_, receiver_not_string_); |
| 3885 | 3908 |
| 3886 // Fetch the instance type of the receiver into result register. | 3909 // Fetch the instance type of the receiver into result register. |
| 3887 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 3910 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 3888 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 3911 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 3889 // If the receiver is not a string trigger the non-string case. | 3912 // If the receiver is not a string trigger the non-string case. |
| 3890 __ testb(result_, Immediate(kIsNotStringMask)); | 3913 __ testb(result_, Immediate(kIsNotStringMask)); |
| 3891 __ j(not_zero, receiver_not_string_); | 3914 __ j(not_zero, receiver_not_string_); |
| 3892 | 3915 |
| 3893 // If the index is non-smi trigger the non-smi case. | 3916 // If the index is non-smi trigger the non-smi case. |
| 3894 __ JumpIfNotSmi(index_, &index_not_smi_); | 3917 __ JumpIfNotSmi(index_, &index_not_smi_); |
| 3895 | 3918 |
| 3896 // Put smi-tagged index into scratch register. | 3919 // Put smi-tagged index into scratch register. |
| 3897 __ movq(scratch_, index_); | 3920 __ movq(scratch_, index_); |
| 3898 __ bind(&got_smi_index_); | 3921 __ bind(&got_smi_index_); |
| 3899 | 3922 |
| 3900 // Check for index out of range. | 3923 // Check for index out of range. |
| 3901 __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset)); | 3924 __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset)); |
| 3902 __ j(above_equal, index_out_of_range_); | 3925 __ j(above_equal, index_out_of_range_); |
| 3903 | 3926 |
| 3904 // We need special handling for non-flat strings. | 3927 // We need special handling for non-flat strings. |
| 3905 STATIC_ASSERT(kSeqStringTag == 0); | 3928 STATIC_ASSERT(kSeqStringTag == 0); |
| 3906 __ testb(result_, Immediate(kStringRepresentationMask)); | 3929 __ testb(result_, Immediate(kStringRepresentationMask)); |
| 3907 __ j(zero, &flat_string); | 3930 __ j(zero, &flat_string); |
| 3908 | 3931 |
| 3909 // Handle non-flat strings. | 3932 // Handle non-flat strings. |
| 3910 __ testb(result_, Immediate(kIsConsStringMask)); | 3933 __ and_(result_, Immediate(kStringRepresentationMask)); |
| 3911 __ j(zero, &call_runtime_); | 3934 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 3935 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 3936 __ cmpb(result_, Immediate(kExternalStringTag)); |
| 3937 __ j(greater, &sliced_string); |
| 3938 __ j(equal, &call_runtime_); |
| 3912 | 3939 |
| 3913 // ConsString. | 3940 // ConsString. |
| 3914 // Check whether the right hand side is the empty string (i.e. if | 3941 // Check whether the right hand side is the empty string (i.e. if |
| 3915 // this is really a flat string in a cons string). If that is not | 3942 // this is really a flat string in a cons string). If that is not |
| 3916 // the case we would rather go to the runtime system now to flatten | 3943 // the case we would rather go to the runtime system now to flatten |
| 3917 // the string. | 3944 // the string. |
| 3945 Label assure_seq_string; |
| 3918 __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset), | 3946 __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset), |
| 3919 Heap::kEmptyStringRootIndex); | 3947 Heap::kEmptyStringRootIndex); |
| 3920 __ j(not_equal, &call_runtime_); | 3948 __ j(not_equal, &call_runtime_); |
| 3921 // Get the first of the two strings and load its instance type. | 3949 // Get the first of the two strings and load its instance type. |
| 3922 __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset)); | 3950 __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset)); |
| 3951 __ jmp(&assure_seq_string, Label::kNear); |
| 3952 |
| 3953 // SlicedString, unpack and add offset. |
| 3954 __ bind(&sliced_string); |
| 3955 __ addq(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset)); |
| 3956 __ movq(object_, FieldOperand(object_, SlicedString::kParentOffset)); |
| 3957 |
| 3958 __ bind(&assure_seq_string); |
| 3923 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 3959 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 3924 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 3960 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 3925 // If the first cons component is also non-flat, then go to runtime. | 3961 // If the first cons component is also non-flat, then go to runtime. |
| 3926 STATIC_ASSERT(kSeqStringTag == 0); | 3962 STATIC_ASSERT(kSeqStringTag == 0); |
| 3927 __ testb(result_, Immediate(kStringRepresentationMask)); | 3963 __ testb(result_, Immediate(kStringRepresentationMask)); |
| 3928 __ j(not_zero, &call_runtime_); | 3964 __ j(not_zero, &call_runtime_); |
| 3965 __ jmp(&flat_string); |
| 3929 | 3966 |
| 3930 // Check for 1-byte or 2-byte string. | 3967 // Check for 1-byte or 2-byte string. |
| 3931 __ bind(&flat_string); | 3968 __ bind(&flat_string); |
| 3932 STATIC_ASSERT(kAsciiStringTag != 0); | 3969 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 3970 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 3933 __ testb(result_, Immediate(kStringEncodingMask)); | 3971 __ testb(result_, Immediate(kStringEncodingMask)); |
| 3934 __ j(not_zero, &ascii_string); | 3972 __ j(not_zero, &ascii_string); |
| 3935 | 3973 |
| 3936 // 2-byte string. | 3974 // 2-byte string. |
| 3937 // Load the 2-byte character code into the result register. | 3975 // Load the 2-byte character code into the result register. |
| 3938 __ SmiToInteger32(scratch_, scratch_); | 3976 __ SmiToInteger32(scratch_, scratch_); |
| 3939 __ movzxwl(result_, FieldOperand(object_, | 3977 __ movzxwl(result_, FieldOperand(object_, |
| 3940 scratch_, times_2, | 3978 scratch_, times_2, |
| 3941 SeqTwoByteString::kHeaderSize)); | 3979 SeqTwoByteString::kHeaderSize)); |
| 3942 __ jmp(&got_char_code); | 3980 __ jmp(&got_char_code); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4179 // If result is not supposed to be flat, allocate a cons string object. If | 4217 // If result is not supposed to be flat, allocate a cons string object. If |
| 4180 // both strings are ascii the result is an ascii cons string. | 4218 // both strings are ascii the result is an ascii cons string. |
| 4181 // rax: first string | 4219 // rax: first string |
| 4182 // rbx: length of resulting flat string | 4220 // rbx: length of resulting flat string |
| 4183 // rdx: second string | 4221 // rdx: second string |
| 4184 // r8: instance type of first string | 4222 // r8: instance type of first string |
| 4185 // r9: instance type of second string | 4223 // r9: instance type of second string |
| 4186 Label non_ascii, allocated, ascii_data; | 4224 Label non_ascii, allocated, ascii_data; |
| 4187 __ movl(rcx, r8); | 4225 __ movl(rcx, r8); |
| 4188 __ and_(rcx, r9); | 4226 __ and_(rcx, r9); |
| 4189 STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); | 4227 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 4190 __ testl(rcx, Immediate(kAsciiStringTag)); | 4228 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 4229 __ testl(rcx, Immediate(kStringEncodingMask)); |
| 4191 __ j(zero, &non_ascii); | 4230 __ j(zero, &non_ascii); |
| 4192 __ bind(&ascii_data); | 4231 __ bind(&ascii_data); |
| 4193 // Allocate an acsii cons string. | 4232 // Allocate an acsii cons string. |
| 4194 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); | 4233 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); |
| 4195 __ bind(&allocated); | 4234 __ bind(&allocated); |
| 4196 // Fill the fields of the cons string. | 4235 // Fill the fields of the cons string. |
| 4197 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); | 4236 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); |
| 4198 __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), | 4237 __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), |
| 4199 Immediate(String::kEmptyHashField)); | 4238 Immediate(String::kEmptyHashField)); |
| 4200 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); | 4239 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); |
| 4201 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | 4240 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); |
| 4202 __ movq(rax, rcx); | 4241 __ movq(rax, rcx); |
| 4203 __ IncrementCounter(counters->string_add_native(), 1); | 4242 __ IncrementCounter(counters->string_add_native(), 1); |
| 4204 __ ret(2 * kPointerSize); | 4243 __ ret(2 * kPointerSize); |
| 4205 __ bind(&non_ascii); | 4244 __ bind(&non_ascii); |
| 4206 // At least one of the strings is two-byte. Check whether it happens | 4245 // At least one of the strings is two-byte. Check whether it happens |
| 4207 // to contain only ascii characters. | 4246 // to contain only ascii characters. |
| 4208 // rcx: first instance type AND second instance type. | 4247 // rcx: first instance type AND second instance type. |
| 4209 // r8: first instance type. | 4248 // r8: first instance type. |
| 4210 // r9: second instance type. | 4249 // r9: second instance type. |
| 4211 __ testb(rcx, Immediate(kAsciiDataHintMask)); | 4250 __ testb(rcx, Immediate(kAsciiDataHintMask)); |
| 4212 __ j(not_zero, &ascii_data); | 4251 __ j(not_zero, &ascii_data); |
| 4213 __ xor_(r8, r9); | 4252 __ xor_(r8, r9); |
| 4214 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 4253 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
| 4215 __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); | 4254 __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); |
| 4216 __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); | 4255 __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); |
| 4217 __ j(equal, &ascii_data); | 4256 __ j(equal, &ascii_data); |
| 4218 // Allocate a two byte cons string. | 4257 // Allocate a two byte cons string. |
| 4219 __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); | 4258 __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime); |
| 4220 __ jmp(&allocated); | 4259 __ jmp(&allocated); |
| 4221 | 4260 |
| 4222 // Handle creating a flat result. First check that both strings are not | 4261 // Handle creating a flat result. First check that both strings are not |
| 4223 // external strings. | 4262 // external strings. |
| 4224 // rax: first string | 4263 // rax: first string |
| 4225 // rbx: length of resulting flat string as smi | 4264 // rbx: length of resulting flat string as smi |
| 4226 // rdx: second string | 4265 // rdx: second string |
| 4227 // r8: instance type of first string | 4266 // r8: instance type of first string |
| 4228 // r9: instance type of first string | 4267 // r9: instance type of first string |
| 4229 __ bind(&string_add_flat_result); | 4268 __ bind(&string_add_flat_result); |
| 4230 __ SmiToInteger32(rbx, rbx); | 4269 __ SmiToInteger32(rbx, rbx); |
| 4231 __ movl(rcx, r8); | 4270 __ movl(rcx, r8); |
| 4232 __ and_(rcx, Immediate(kStringRepresentationMask)); | 4271 __ and_(rcx, Immediate(kStringRepresentationMask)); |
| 4233 __ cmpl(rcx, Immediate(kExternalStringTag)); | 4272 __ cmpl(rcx, Immediate(kExternalStringTag)); |
| 4234 __ j(equal, &string_add_runtime); | 4273 __ j(equal, &string_add_runtime); |
| 4235 __ movl(rcx, r9); | 4274 __ movl(rcx, r9); |
| 4236 __ and_(rcx, Immediate(kStringRepresentationMask)); | 4275 __ and_(rcx, Immediate(kStringRepresentationMask)); |
| 4237 __ cmpl(rcx, Immediate(kExternalStringTag)); | 4276 __ cmpl(rcx, Immediate(kExternalStringTag)); |
| 4238 __ j(equal, &string_add_runtime); | 4277 __ j(equal, &string_add_runtime); |
| 4278 // We cannot encounter sliced strings here since: |
| 4279 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
| 4239 // Now check if both strings are ascii strings. | 4280 // Now check if both strings are ascii strings. |
| 4240 // rax: first string | 4281 // rax: first string |
| 4241 // rbx: length of resulting flat string | 4282 // rbx: length of resulting flat string |
| 4242 // rdx: second string | 4283 // rdx: second string |
| 4243 // r8: instance type of first string | 4284 // r8: instance type of first string |
| 4244 // r9: instance type of second string | 4285 // r9: instance type of second string |
| 4245 Label non_ascii_string_add_flat_result; | 4286 Label non_ascii_string_add_flat_result; |
| 4246 STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); | 4287 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 4247 __ testl(r8, Immediate(kAsciiStringTag)); | 4288 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 4289 __ testl(r8, Immediate(kStringEncodingMask)); |
| 4248 __ j(zero, &non_ascii_string_add_flat_result); | 4290 __ j(zero, &non_ascii_string_add_flat_result); |
| 4249 __ testl(r9, Immediate(kAsciiStringTag)); | 4291 __ testl(r9, Immediate(kStringEncodingMask)); |
| 4250 __ j(zero, &string_add_runtime); | 4292 __ j(zero, &string_add_runtime); |
| 4251 | 4293 |
| 4252 __ bind(&make_flat_ascii_string); | 4294 __ bind(&make_flat_ascii_string); |
| 4253 // Both strings are ascii strings. As they are short they are both flat. | 4295 // Both strings are ascii strings. As they are short they are both flat. |
| 4254 __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime); | 4296 __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime); |
| 4255 // rcx: result string | 4297 // rcx: result string |
| 4256 __ movq(rbx, rcx); | 4298 __ movq(rbx, rcx); |
| 4257 // Locate first character of result. | 4299 // Locate first character of result. |
| 4258 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4300 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 4259 // Locate first character of first argument | 4301 // Locate first character of first argument |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4277 __ IncrementCounter(counters->string_add_native(), 1); | 4319 __ IncrementCounter(counters->string_add_native(), 1); |
| 4278 __ ret(2 * kPointerSize); | 4320 __ ret(2 * kPointerSize); |
| 4279 | 4321 |
| 4280 // Handle creating a flat two byte result. | 4322 // Handle creating a flat two byte result. |
| 4281 // rax: first string - known to be two byte | 4323 // rax: first string - known to be two byte |
| 4282 // rbx: length of resulting flat string | 4324 // rbx: length of resulting flat string |
| 4283 // rdx: second string | 4325 // rdx: second string |
| 4284 // r8: instance type of first string | 4326 // r8: instance type of first string |
| 4285 // r9: instance type of first string | 4327 // r9: instance type of first string |
| 4286 __ bind(&non_ascii_string_add_flat_result); | 4328 __ bind(&non_ascii_string_add_flat_result); |
| 4287 __ and_(r9, Immediate(kAsciiStringTag)); | 4329 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 4330 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 4331 __ and_(r9, Immediate(kStringEncodingMask)); |
| 4288 __ j(not_zero, &string_add_runtime); | 4332 __ j(not_zero, &string_add_runtime); |
| 4289 // Both strings are two byte strings. As they are short they are both | 4333 // Both strings are two byte strings. As they are short they are both |
| 4290 // flat. | 4334 // flat. |
| 4291 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime); | 4335 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime); |
| 4292 // rcx: result string | 4336 // rcx: result string |
| 4293 __ movq(rbx, rcx); | 4337 __ movq(rbx, rcx); |
| 4294 // Locate first character of result. | 4338 // Locate first character of result. |
| 4295 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 4339 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 4296 // Locate first character of first argument. | 4340 // Locate first character of first argument. |
| 4297 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); | 4341 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4686 masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string); | 4730 masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string); |
| 4687 __ ret(3 * kPointerSize); | 4731 __ ret(3 * kPointerSize); |
| 4688 | 4732 |
| 4689 __ bind(&make_two_character_string); | 4733 __ bind(&make_two_character_string); |
| 4690 // Setup registers for allocating the two character string. | 4734 // Setup registers for allocating the two character string. |
| 4691 __ movq(rax, Operand(rsp, kStringOffset)); | 4735 __ movq(rax, Operand(rsp, kStringOffset)); |
| 4692 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 4736 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4693 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 4737 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 4694 __ Set(rcx, 2); | 4738 __ Set(rcx, 2); |
| 4695 | 4739 |
| 4696 __ bind(&result_longer_than_two); | 4740 if (FLAG_string_slices) { |
| 4741 Label copy_routine; |
| 4742 // If coming from the make_two_character_string path, the string |
| 4743 // is too short to be sliced anyways. |
| 4744 STATIC_ASSERT(2 < SlicedString::kMinLength); |
| 4745 __ jmp(©_routine); |
| 4746 __ bind(&result_longer_than_two); |
| 4747 |
| 4748 // rax: string |
| 4749 // rbx: instance type |
| 4750 // rcx: sub string length |
| 4751 // rdx: from index (smi) |
| 4752 Label allocate_slice, sliced_string, seq_string; |
| 4753 __ cmpq(rcx, Immediate(SlicedString::kMinLength)); |
| 4754 // Short slice. Copy instead of slicing. |
| 4755 __ j(less, ©_routine); |
| 4756 STATIC_ASSERT(kSeqStringTag == 0); |
| 4757 __ testb(rbx, Immediate(kStringRepresentationMask)); |
| 4758 __ j(zero, &seq_string, Label::kNear); |
| 4759 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
| 4760 STATIC_ASSERT(kIsIndirectStringMask != 0); |
| 4761 __ testb(rbx, Immediate(kIsIndirectStringMask)); |
| 4762 // External string. Jump to runtime. |
| 4763 __ j(zero, &runtime); |
| 4764 |
| 4765 __ testb(rbx, Immediate(kSlicedNotConsMask)); |
| 4766 __ j(not_zero, &sliced_string, Label::kNear); |
| 4767 // Cons string. Check whether it is flat, then fetch first part. |
| 4768 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), |
| 4769 Heap::kEmptyStringRootIndex); |
| 4770 __ j(not_equal, &runtime); |
| 4771 __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); |
| 4772 __ jmp(&allocate_slice, Label::kNear); |
| 4773 |
| 4774 __ bind(&sliced_string); |
| 4775 // Sliced string. Fetch parent and correct start index by offset. |
| 4776 __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); |
| 4777 __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); |
| 4778 __ jmp(&allocate_slice, Label::kNear); |
| 4779 |
| 4780 __ bind(&seq_string); |
| 4781 // Sequential string. Just move string to the right register. |
| 4782 __ movq(rdi, rax); |
| 4783 |
| 4784 __ bind(&allocate_slice); |
| 4785 // edi: underlying subject string |
| 4786 // ebx: instance type of original subject string |
| 4787 // edx: offset |
| 4788 // ecx: length |
| 4789 // Allocate new sliced string. At this point we do not reload the instance |
| 4790 // type including the string encoding because we simply rely on the info |
| 4791 // provided by the original string. It does not matter if the original |
| 4792 // string's encoding is wrong because we always have to recheck encoding of |
| 4793 // the newly created string's parent anyways due to externalized strings. |
| 4794 Label two_byte_slice, set_slice_header; |
| 4795 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 4796 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 4797 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 4798 __ j(zero, &two_byte_slice, Label::kNear); |
| 4799 __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime); |
| 4800 __ jmp(&set_slice_header, Label::kNear); |
| 4801 __ bind(&two_byte_slice); |
| 4802 __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime); |
| 4803 __ bind(&set_slice_header); |
| 4804 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); |
| 4805 __ Integer32ToSmi(rcx, rcx); |
| 4806 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); |
| 4807 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); |
| 4808 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), |
| 4809 Immediate(String::kEmptyHashField)); |
| 4810 __ jmp(&return_rax); |
| 4811 |
| 4812 __ bind(©_routine); |
| 4813 } else { |
| 4814 __ bind(&result_longer_than_two); |
| 4815 } |
| 4697 | 4816 |
| 4698 // rax: string | 4817 // rax: string |
| 4699 // rbx: instance type | 4818 // rbx: instance type |
| 4700 // rcx: result string length | 4819 // rcx: result string length |
| 4701 // Check for flat ascii string | 4820 // Check for flat ascii string |
| 4702 Label non_ascii_flat; | 4821 Label non_ascii_flat; |
| 4703 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat); | 4822 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat); |
| 4704 | 4823 |
| 4705 // Allocate the result. | 4824 // Allocate the result. |
| 4706 __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); | 4825 __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); |
| (...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5573 | 5692 |
| 5574 // Fall through when we need to inform the incremental marker. | 5693 // Fall through when we need to inform the incremental marker. |
| 5575 } | 5694 } |
| 5576 | 5695 |
| 5577 | 5696 |
| 5578 #undef __ | 5697 #undef __ |
| 5579 | 5698 |
| 5580 } } // namespace v8::internal | 5699 } } // namespace v8::internal |
| 5581 | 5700 |
| 5582 #endif // V8_TARGET_ARCH_X64 | 5701 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |