| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 2938 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2949 ExternalReference::address_of_regexp_stack_memory_size(isolate); | 2949 ExternalReference::address_of_regexp_stack_memory_size(isolate); |
| 2950 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); | 2950 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); |
| 2951 __ testq(kScratchRegister, kScratchRegister); | 2951 __ testq(kScratchRegister, kScratchRegister); |
| 2952 __ j(zero, &runtime); | 2952 __ j(zero, &runtime); |
| 2953 | 2953 |
| 2954 // Check that the first argument is a JSRegExp object. | 2954 // Check that the first argument is a JSRegExp object. |
| 2955 __ movq(rax, Operand(rsp, kJSRegExpOffset)); | 2955 __ movq(rax, Operand(rsp, kJSRegExpOffset)); |
| 2956 __ JumpIfSmi(rax, &runtime); | 2956 __ JumpIfSmi(rax, &runtime); |
| 2957 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); | 2957 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); |
| 2958 __ j(not_equal, &runtime); | 2958 __ j(not_equal, &runtime); |
| 2959 |
| 2959 // Check that the RegExp has been compiled (data contains a fixed array). | 2960 // Check that the RegExp has been compiled (data contains a fixed array). |
| 2960 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); | 2961 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 2961 if (FLAG_debug_code) { | 2962 if (FLAG_debug_code) { |
| 2962 Condition is_smi = masm->CheckSmi(rax); | 2963 Condition is_smi = masm->CheckSmi(rax); |
| 2963 __ Check(NegateCondition(is_smi), | 2964 __ Check(NegateCondition(is_smi), |
| 2964 "Unexpected type for RegExp data, FixedArray expected"); | 2965 "Unexpected type for RegExp data, FixedArray expected"); |
| 2965 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); | 2966 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); |
| 2966 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); | 2967 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |
| 2967 } | 2968 } |
| 2968 | 2969 |
| 2969 // rax: RegExp data (FixedArray) | 2970 // rax: RegExp data (FixedArray) |
| 2970 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 2971 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
| 2971 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); | 2972 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); |
| 2972 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); | 2973 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); |
| 2973 __ j(not_equal, &runtime); | 2974 __ j(not_equal, &runtime); |
| 2974 | 2975 |
| 2975 // rax: RegExp data (FixedArray) | 2976 // rax: RegExp data (FixedArray) |
| 2976 // Check that the number of captures fit in the static offsets vector buffer. | 2977 // Check that the number of captures fit in the static offsets vector buffer. |
| 2977 __ SmiToInteger32(rdx, | 2978 __ SmiToInteger32(rdx, |
| 2978 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); | 2979 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); |
| 2979 // Calculate number of capture registers (number_of_captures + 1) * 2. | 2980 // Check (number_of_captures + 1) * 2 <= offsets vector size |
| 2980 __ leal(rdx, Operand(rdx, rdx, times_1, 2)); | 2981 // Or number_of_captures <= offsets vector size / 2 - 1 |
| 2981 // Check that the static offsets vector buffer is large enough. | 2982 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
| 2982 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize)); | 2983 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); |
| 2983 __ j(above, &runtime); | 2984 __ j(above, &runtime); |
| 2984 | 2985 |
| 2985 // rax: RegExp data (FixedArray) | |
| 2986 // rdx: Number of capture registers | |
| 2987 // Check that the second argument is a string. | |
| 2988 __ movq(rdi, Operand(rsp, kSubjectOffset)); | |
| 2989 __ JumpIfSmi(rdi, &runtime); | |
| 2990 Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx); | |
| 2991 __ j(NegateCondition(is_string), &runtime); | |
| 2992 | |
| 2993 // rdi: Subject string. | |
| 2994 // rax: RegExp data (FixedArray). | |
| 2995 // rdx: Number of capture registers. | |
| 2996 // Check that the third argument is a positive smi less than the string | |
| 2997 // length. A negative value will be greater (unsigned comparison). | |
| 2998 __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); | |
| 2999 __ JumpIfNotSmi(rbx, &runtime); | |
| 3000 __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset)); | |
| 3001 __ j(above_equal, &runtime); | |
| 3002 | |
| 3003 // rax: RegExp data (FixedArray) | |
| 3004 // rdx: Number of capture registers | |
| 3005 // Check that the fourth object is a JSArray object. | |
| 3006 __ movq(rdi, Operand(rsp, kLastMatchInfoOffset)); | |
| 3007 __ JumpIfSmi(rdi, &runtime); | |
| 3008 __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister); | |
| 3009 __ j(not_equal, &runtime); | |
| 3010 // Check that the JSArray is in fast case. | |
| 3011 __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset)); | |
| 3012 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); | |
| 3013 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
| 3014 Heap::kFixedArrayMapRootIndex); | |
| 3015 __ j(not_equal, &runtime); | |
| 3016 // Check that the last match info has space for the capture registers and the | |
| 3017 // additional information. Ensure no overflow in add. | |
| 3018 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | |
| 3019 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); | |
| 3020 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); | |
| 3021 __ cmpl(rdx, rdi); | |
| 3022 __ j(greater, &runtime); | |
| 3023 | |
| 3024 // Reset offset for possibly sliced string. | 2986 // Reset offset for possibly sliced string. |
| 3025 __ Set(r14, 0); | 2987 __ Set(r14, 0); |
| 3026 // rax: RegExp data (FixedArray) | |
| 3027 // Check the representation and encoding of the subject string. | |
| 3028 Label seq_ascii_string, seq_two_byte_string, check_code; | |
| 3029 __ movq(rdi, Operand(rsp, kSubjectOffset)); | 2988 __ movq(rdi, Operand(rsp, kSubjectOffset)); |
| 3030 // Make a copy of the original subject string. | 2989 __ JumpIfSmi(rdi, &runtime); |
| 3031 __ movq(r15, rdi); | 2990 __ movq(r15, rdi); // Make a copy of the original subject string. |
| 3032 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2991 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 3033 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2992 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 3034 // First check for flat two byte string. | 2993 // rax: RegExp data (FixedArray) |
| 2994 // rdi: subject string |
| 2995 // r15: subject string |
| 2996 // Handle subject string according to its encoding and representation: |
| 2997 // (1) Sequential two byte? If yes, go to (9). |
| 2998 // (2) Sequential one byte? If yes, go to (6). |
| 2999 // (3) Anything but sequential or cons? If yes, go to (7). |
| 3000 // (4) Cons string. Replace subject with first string. |
| 3001 // (5a) Is subject two byte? If yes, go to (9). |
| 3002 // (5b) Is subject external? If yes, go to (8). |
| 3003 // (6) One byte sequential. Load regexp code for one byte. |
| 3004 // (E) Carry on. |
| 3005 /// [...] |
| 3006 |
| 3007 // Deferred code at the end of the stub: |
| 3008 // (7) Not a long external string? If yes, go to (10). |
| 3009 // (8) External string. Make it, offset-wise, look like a sequential string. |
| 3010 // (8a) Is the external string one byte? If yes, go to (6). |
| 3011 // (9) Two byte sequential. Load regexp code for one byte. Go to (E). |
| 3012 // (10) Short external string or not a string? If yes, bail out to runtime. |
| 3013 // (11) Sliced string. Replace subject with parent. Go to (5a). |
| 3014 |
| 3015 Label seq_one_byte_string /* 6 */, seq_two_byte_string /* 9 */, |
| 3016 external_string /* 8 */, check_underlying /* 5a */, |
| 3017 not_seq_nor_cons /* 7 */, check_code /* E */, |
| 3018 not_long_external /* 10 */; |
| 3019 |
| 3020 // (1) Sequential two byte? If yes, go to (9). |
| 3035 __ andb(rbx, Immediate(kIsNotStringMask | | 3021 __ andb(rbx, Immediate(kIsNotStringMask | |
| 3036 kStringRepresentationMask | | 3022 kStringRepresentationMask | |
| 3037 kStringEncodingMask | | 3023 kStringEncodingMask | |
| 3038 kShortExternalStringMask)); | 3024 kShortExternalStringMask)); |
| 3039 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 3025 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
| 3040 __ j(zero, &seq_two_byte_string, Label::kNear); | 3026 __ j(zero, &seq_two_byte_string); // Go to (9). |
| 3041 // Any other flat string must be a flat ASCII string. None of the following | 3027 |
| 3042 // string type tests will succeed if subject is not a string or a short | 3028 // (2) Sequential one byte? If yes, go to (6). |
| 3043 // external string. | 3029 // Any other sequential string must be one byte. |
| 3044 __ andb(rbx, Immediate(kIsNotStringMask | | 3030 __ andb(rbx, Immediate(kIsNotStringMask | |
| 3045 kStringRepresentationMask | | 3031 kStringRepresentationMask | |
| 3046 kShortExternalStringMask)); | 3032 kShortExternalStringMask)); |
| 3047 __ j(zero, &seq_ascii_string, Label::kNear); | 3033 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (6). |
| 3048 | 3034 |
| 3049 // rbx: whether subject is a string and if yes, its string representation | 3035 // (3) Anything but sequential or cons? If yes, go to (7). |
| 3050 // Check for flat cons string or sliced string. | 3036 // We check whether the subject string is a cons, since sequential strings |
| 3051 // A flat cons string is a cons string where the second part is the empty | 3037 // have already been covered. |
| 3052 // string. In that case the subject string is just the first part of the cons | |
| 3053 // string. Also in this case the first part of the cons string is known to be | |
| 3054 // a sequential string or an external string. | |
| 3055 // In the case of a sliced string its offset has to be taken into account. | |
| 3056 Label cons_string, external_string, check_encoding; | |
| 3057 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 3038 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 3058 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | 3039 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 3059 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | 3040 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); |
| 3060 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | 3041 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); |
| 3061 __ cmpq(rbx, Immediate(kExternalStringTag)); | 3042 __ cmpq(rbx, Immediate(kExternalStringTag)); |
| 3062 __ j(less, &cons_string, Label::kNear); | 3043 __ j(greater_equal, ¬_seq_nor_cons); // Go to (7). |
| 3063 __ j(equal, &external_string); | |
| 3064 | 3044 |
| 3065 // Catch non-string subject or short external string. | 3045 // (4) Cons string. Check that it's flat. |
| 3066 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | 3046 // Replace subject with first string and reload instance type. |
| 3067 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); | |
| 3068 __ j(not_zero, &runtime); | |
| 3069 | |
| 3070 // String is sliced. | |
| 3071 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); | |
| 3072 __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); | |
| 3073 // r14: slice offset | |
| 3074 // r15: original subject string | |
| 3075 // rdi: parent string | |
| 3076 __ jmp(&check_encoding, Label::kNear); | |
| 3077 // String is a cons string, check whether it is flat. | |
| 3078 __ bind(&cons_string); | |
| 3079 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | 3047 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
| 3080 Heap::kEmptyStringRootIndex); | 3048 Heap::kEmptyStringRootIndex); |
| 3081 __ j(not_equal, &runtime); | 3049 __ j(not_equal, &runtime); |
| 3082 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | 3050 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
| 3083 // rdi: first part of cons string or parent of sliced string. | 3051 __ bind(&check_underlying); |
| 3084 // rbx: map of first part of cons string or map of parent of sliced string. | |
| 3085 // Is first part of cons or parent of slice a flat two byte string? | |
| 3086 __ bind(&check_encoding); | |
| 3087 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 3052 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 3088 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 3053 __ movq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 3089 Immediate(kStringRepresentationMask | kStringEncodingMask)); | 3054 |
| 3055 // (5a) Is subject two byte? If yes, go to (9). |
| 3056 __ testb(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 3090 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 3057 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
| 3091 __ j(zero, &seq_two_byte_string, Label::kNear); | 3058 __ j(zero, &seq_two_byte_string); // Go to (9). |
| 3092 // Any other flat string must be sequential ASCII or external. | 3059 // (5b) Is subject external? If yes, go to (8). |
| 3093 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 3060 __ testb(rbx, Immediate(kStringRepresentationMask)); |
| 3094 Immediate(kStringRepresentationMask)); | 3061 // The underlying external string is never a short external string. |
| 3095 __ j(not_zero, &external_string); | 3062 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength); |
| 3063 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength); |
| 3064 __ j(not_zero, &external_string); // Go to (8) |
| 3096 | 3065 |
| 3097 __ bind(&seq_ascii_string); | 3066 // (6) One byte sequential. Load regexp code for one byte. |
| 3098 // rdi: subject string (sequential ASCII) | 3067 __ bind(&seq_one_byte_string); |
| 3099 // rax: RegExp data (FixedArray) | 3068 // rax: RegExp data (FixedArray) |
| 3100 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); | 3069 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); |
| 3101 __ Set(rcx, 1); // Type is ASCII. | 3070 __ Set(rcx, 1); // Type is one byte. |
| 3102 __ jmp(&check_code, Label::kNear); | |
| 3103 | 3071 |
| 3104 __ bind(&seq_two_byte_string); | 3072 // (E) Carry on. String handling is done. |
| 3105 // rdi: subject string (flat two-byte) | |
| 3106 // rax: RegExp data (FixedArray) | |
| 3107 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | |
| 3108 __ Set(rcx, 0); // Type is two byte. | |
| 3109 | |
| 3110 __ bind(&check_code); | 3073 __ bind(&check_code); |
| 3074 // r11: irregexp code |
| 3111 // Check that the irregexp code has been generated for the actual string | 3075 // Check that the irregexp code has been generated for the actual string |
| 3112 // encoding. If it has, the field contains a code object otherwise it contains | 3076 // encoding. If it has, the field contains a code object otherwise it contains |
| 3113 // smi (code flushing support) | 3077 // smi (code flushing support) |
| 3114 __ JumpIfSmi(r11, &runtime); | 3078 __ JumpIfSmi(r11, &runtime); |
| 3115 | 3079 |
| 3116 // rdi: subject string | 3080 // rdi: sequential subject string (or look-alike, external string) |
| 3081 // r15: original subject string |
| 3117 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); | 3082 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 3118 // r11: code | 3083 // r11: code |
| 3119 // Load used arguments before starting to push arguments for call to native | 3084 // Load used arguments before starting to push arguments for call to native |
| 3120 // RegExp code to avoid handling changing stack height. | 3085 // RegExp code to avoid handling changing stack height. |
| 3121 __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset)); | 3086 // We have to use r15 instead of rdi to load the length because rdi might |
| 3087 // have been only made to look like a sequential string when it actually |
| 3088 // is an external string. |
| 3089 __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); |
| 3090 __ JumpIfNotSmi(rbx, &runtime); |
| 3091 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); |
| 3092 __ j(above_equal, &runtime); |
| 3093 __ SmiToInteger64(rbx, rbx); |
| 3122 | 3094 |
| 3123 // rdi: subject string | 3095 // rdi: subject string |
| 3124 // rbx: previous index | 3096 // rbx: previous index |
| 3125 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 3097 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); |
| 3126 // r11: code | 3098 // r11: code |
| 3127 // All checks done. Now push arguments for native regexp code. | 3099 // All checks done. Now push arguments for native regexp code. |
| 3128 Counters* counters = masm->isolate()->counters(); | 3100 Counters* counters = masm->isolate()->counters(); |
| 3129 __ IncrementCounter(counters->regexp_entry_native(), 1); | 3101 __ IncrementCounter(counters->regexp_entry_native(), 1); |
| 3130 | 3102 |
| 3131 // Isolates: note we add an additional parameter here (isolate pointer). | 3103 // Isolates: note we add an additional parameter here (isolate pointer). |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3250 // Load RegExp data. | 3222 // Load RegExp data. |
| 3251 __ bind(&success); | 3223 __ bind(&success); |
| 3252 __ movq(rax, Operand(rsp, kJSRegExpOffset)); | 3224 __ movq(rax, Operand(rsp, kJSRegExpOffset)); |
| 3253 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); | 3225 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 3254 __ SmiToInteger32(rax, | 3226 __ SmiToInteger32(rax, |
| 3255 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); | 3227 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 3256 // Calculate number of capture registers (number_of_captures + 1) * 2. | 3228 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 3257 __ leal(rdx, Operand(rax, rax, times_1, 2)); | 3229 __ leal(rdx, Operand(rax, rax, times_1, 2)); |
| 3258 | 3230 |
| 3259 // rdx: Number of capture registers | 3231 // rdx: Number of capture registers |
| 3260 // Load last_match_info which is still known to be a fast case JSArray. | 3232 // Check that the fourth object is a JSArray object. |
| 3261 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); | 3233 __ movq(r15, Operand(rsp, kLastMatchInfoOffset)); |
| 3262 __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset)); | 3234 __ JumpIfSmi(r15, &runtime); |
| 3235 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister); |
| 3236 __ j(not_equal, &runtime); |
| 3237 // Check that the JSArray is in fast case. |
| 3238 __ movq(rbx, FieldOperand(r15, JSArray::kElementsOffset)); |
| 3239 __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 3240 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); |
| 3241 __ j(not_equal, &runtime); |
| 3242 // Check that the last match info has space for the capture registers and the |
| 3243 // additional information. Ensure no overflow in add. |
| 3244 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 3245 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 3246 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 3247 __ cmpl(rdx, rax); |
| 3248 __ j(greater, &runtime); |
| 3263 | 3249 |
| 3264 // rbx: last_match_info backing store (FixedArray) | 3250 // rbx: last_match_info backing store (FixedArray) |
| 3265 // rdx: number of capture registers | 3251 // rdx: number of capture registers |
| 3266 // Store the capture count. | 3252 // Store the capture count. |
| 3267 __ Integer32ToSmi(kScratchRegister, rdx); | 3253 __ Integer32ToSmi(kScratchRegister, rdx); |
| 3268 __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), | 3254 __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), |
| 3269 kScratchRegister); | 3255 kScratchRegister); |
| 3270 // Store last subject and last input. | 3256 // Store last subject and last input. |
| 3271 __ movq(rax, Operand(rsp, kSubjectOffset)); | 3257 __ movq(rax, Operand(rsp, kSubjectOffset)); |
| 3272 __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); | 3258 __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); |
| 3259 __ movq(rcx, rax); |
| 3273 __ RecordWriteField(rbx, | 3260 __ RecordWriteField(rbx, |
| 3274 RegExpImpl::kLastSubjectOffset, | 3261 RegExpImpl::kLastSubjectOffset, |
| 3275 rax, | 3262 rax, |
| 3276 rdi, | 3263 rdi, |
| 3277 kDontSaveFPRegs); | 3264 kDontSaveFPRegs); |
| 3278 __ movq(rax, Operand(rsp, kSubjectOffset)); | 3265 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rcx); |
| 3279 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); | |
| 3280 __ RecordWriteField(rbx, | 3266 __ RecordWriteField(rbx, |
| 3281 RegExpImpl::kLastInputOffset, | 3267 RegExpImpl::kLastInputOffset, |
| 3282 rax, | 3268 rcx, |
| 3283 rdi, | 3269 rdi, |
| 3284 kDontSaveFPRegs); | 3270 kDontSaveFPRegs); |
| 3285 | 3271 |
| 3286 // Get the static offsets vector filled by the native regexp code. | 3272 // Get the static offsets vector filled by the native regexp code. |
| 3287 __ LoadAddress(rcx, | 3273 __ LoadAddress(rcx, |
| 3288 ExternalReference::address_of_static_offsets_vector(isolate)); | 3274 ExternalReference::address_of_static_offsets_vector(isolate)); |
| 3289 | 3275 |
| 3290 // rbx: last_match_info backing store (FixedArray) | 3276 // rbx: last_match_info backing store (FixedArray) |
| 3291 // rcx: offsets vector | 3277 // rcx: offsets vector |
| 3292 // rdx: number of capture registers | 3278 // rdx: number of capture registers |
| 3293 Label next_capture, done; | 3279 Label next_capture, done; |
| 3294 // Capture register counter starts from number of capture registers and | 3280 // Capture register counter starts from number of capture registers and |
| 3295 // counts down until wraping after zero. | 3281 // counts down until wraping after zero. |
| 3296 __ bind(&next_capture); | 3282 __ bind(&next_capture); |
| 3297 __ subq(rdx, Immediate(1)); | 3283 __ subq(rdx, Immediate(1)); |
| 3298 __ j(negative, &done, Label::kNear); | 3284 __ j(negative, &done, Label::kNear); |
| 3299 // Read the value from the static offsets vector buffer and make it a smi. | 3285 // Read the value from the static offsets vector buffer and make it a smi. |
| 3300 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 3286 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
| 3301 __ Integer32ToSmi(rdi, rdi); | 3287 __ Integer32ToSmi(rdi, rdi); |
| 3302 // Store the smi value in the last match info. | 3288 // Store the smi value in the last match info. |
| 3303 __ movq(FieldOperand(rbx, | 3289 __ movq(FieldOperand(rbx, |
| 3304 rdx, | 3290 rdx, |
| 3305 times_pointer_size, | 3291 times_pointer_size, |
| 3306 RegExpImpl::kFirstCaptureOffset), | 3292 RegExpImpl::kFirstCaptureOffset), |
| 3307 rdi); | 3293 rdi); |
| 3308 __ jmp(&next_capture); | 3294 __ jmp(&next_capture); |
| 3309 __ bind(&done); | 3295 __ bind(&done); |
| 3310 | 3296 |
| 3311 // Return last match info. | 3297 // Return last match info. |
| 3312 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); | 3298 __ movq(rax, r15); |
| 3313 __ ret(4 * kPointerSize); | 3299 __ ret(4 * kPointerSize); |
| 3314 | 3300 |
| 3315 __ bind(&exception); | 3301 __ bind(&exception); |
| 3316 // Result must now be exception. If there is no pending exception already a | 3302 // Result must now be exception. If there is no pending exception already a |
| 3317 // stack overflow (on the backtrack stack) was detected in RegExp code but | 3303 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 3318 // haven't created the exception yet. Handle that in the runtime system. | 3304 // haven't created the exception yet. Handle that in the runtime system. |
| 3319 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 3305 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
| 3320 ExternalReference pending_exception_address( | 3306 ExternalReference pending_exception_address( |
| 3321 Isolate::kPendingExceptionAddress, isolate); | 3307 Isolate::kPendingExceptionAddress, isolate); |
| 3322 Operand pending_exception_operand = | 3308 Operand pending_exception_operand = |
| 3323 masm->ExternalOperand(pending_exception_address, rbx); | 3309 masm->ExternalOperand(pending_exception_address, rbx); |
| 3324 __ movq(rax, pending_exception_operand); | 3310 __ movq(rax, pending_exception_operand); |
| 3325 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 3311 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 3326 __ cmpq(rax, rdx); | 3312 __ cmpq(rax, rdx); |
| 3327 __ j(equal, &runtime); | 3313 __ j(equal, &runtime); |
| 3328 __ movq(pending_exception_operand, rdx); | 3314 __ movq(pending_exception_operand, rdx); |
| 3329 | 3315 |
| 3330 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 3316 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
| 3331 Label termination_exception; | 3317 Label termination_exception; |
| 3332 __ j(equal, &termination_exception, Label::kNear); | 3318 __ j(equal, &termination_exception, Label::kNear); |
| 3333 __ Throw(rax); | 3319 __ Throw(rax); |
| 3334 | 3320 |
| 3335 __ bind(&termination_exception); | 3321 __ bind(&termination_exception); |
| 3336 __ ThrowUncatchable(rax); | 3322 __ ThrowUncatchable(rax); |
| 3337 | 3323 |
| 3338 // External string. Short external strings have already been ruled out. | 3324 // Do the runtime call to execute the regexp. |
| 3339 // rdi: subject string (expected to be external) | 3325 __ bind(&runtime); |
| 3340 // rbx: scratch | 3326 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 3327 |
| 3328 // Deferred code for string handling. |
| 3329 // (7) Not a long external string? If yes, go to (10). |
| 3330 __ bind(¬_seq_nor_cons); |
| 3331 // Compare flags are still set from (3). |
| 3332 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). |
| 3333 |
| 3334 // (8) External string. Short external strings have been ruled out. |
| 3341 __ bind(&external_string); | 3335 __ bind(&external_string); |
| 3342 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 3336 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 3343 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 3337 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 3344 if (FLAG_debug_code) { | 3338 if (FLAG_debug_code) { |
| 3345 // Assert that we do not have a cons or slice (indirect strings) here. | 3339 // Assert that we do not have a cons or slice (indirect strings) here. |
| 3346 // Sequential strings have already been ruled out. | 3340 // Sequential strings have already been ruled out. |
| 3347 __ testb(rbx, Immediate(kIsIndirectStringMask)); | 3341 __ testb(rbx, Immediate(kIsIndirectStringMask)); |
| 3348 __ Assert(zero, "external string expected, but not found"); | 3342 __ Assert(zero, "external string expected, but not found"); |
| 3349 } | 3343 } |
| 3350 __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); | 3344 __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); |
| 3351 // Move the pointer so that offset-wise, it looks like a sequential string. | 3345 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 3352 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 3346 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 3353 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3347 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 3354 STATIC_ASSERT(kTwoByteStringTag == 0); | 3348 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 3349 // (8a) Is the external string one byte? If yes, go to (6). |
| 3355 __ testb(rbx, Immediate(kStringEncodingMask)); | 3350 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 3356 __ j(not_zero, &seq_ascii_string); | 3351 __ j(not_zero, &seq_one_byte_string); // Goto (6). |
| 3357 __ jmp(&seq_two_byte_string); | |
| 3358 | 3352 |
| 3359 // Do the runtime call to execute the regexp. | 3353 // rdi: subject string (flat two-byte) |
| 3360 __ bind(&runtime); | 3354 // rax: RegExp data (FixedArray) |
| 3361 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 3355 // (9) Two byte sequential. Load regexp code for one byte. Go to (E). |
| 3356 __ bind(&seq_two_byte_string); |
| 3357 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
| 3358 __ Set(rcx, 0); // Type is two byte. |
| 3359 __ jmp(&check_code); // Go to (E). |
| 3360 |
| 3361 // (10) Not a string or a short external string? If yes, bail out to runtime. |
| 3362 __ bind(¬_long_external); |
| 3363 // Catch non-string subject or short external string. |
| 3364 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); |
| 3365 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); |
| 3366 __ j(not_zero, &runtime); |
| 3367 |
| 3368 // (11) Sliced string. Replace subject with parent. Go to (5a). |
| 3369 // Load offset into r14 and replace subject string with parent. |
| 3370 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); |
| 3371 __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); |
| 3372 __ jmp(&check_underlying); |
| 3362 #endif // V8_INTERPRETED_REGEXP | 3373 #endif // V8_INTERPRETED_REGEXP |
| 3363 } | 3374 } |
| 3364 | 3375 |
| 3365 | 3376 |
| 3366 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 3377 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
| 3367 const int kMaxInlineLength = 100; | 3378 const int kMaxInlineLength = 100; |
| 3368 Label slowcase; | 3379 Label slowcase; |
| 3369 Label done; | 3380 Label done; |
| 3370 __ movq(r8, Operand(rsp, kPointerSize * 3)); | 3381 __ movq(r8, Operand(rsp, kPointerSize * 3)); |
| 3371 __ JumpIfNotSmi(r8, &slowcase); | 3382 __ JumpIfNotSmi(r8, &slowcase); |
| (...skipping 2887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6259 Register object, value, address; | 6270 Register object, value, address; |
| 6260 RememberedSetAction action; | 6271 RememberedSetAction action; |
| 6261 }; | 6272 }; |
| 6262 | 6273 |
| 6263 | 6274 |
| 6264 #define REG(Name) { kRegister_ ## Name ## _Code } | 6275 #define REG(Name) { kRegister_ ## Name ## _Code } |
| 6265 | 6276 |
| 6266 struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { | 6277 struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { |
| 6267 // Used in RegExpExecStub. | 6278 // Used in RegExpExecStub. |
| 6268 { REG(rbx), REG(rax), REG(rdi), EMIT_REMEMBERED_SET }, | 6279 { REG(rbx), REG(rax), REG(rdi), EMIT_REMEMBERED_SET }, |
| 6280 { REG(rbx), REG(rcx), REG(rdi), EMIT_REMEMBERED_SET }, |
| 6269 // Used in CompileArrayPushCall. | 6281 // Used in CompileArrayPushCall. |
| 6270 { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET }, | 6282 { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET }, |
| 6271 // Used in CompileStoreGlobal. | 6283 // Used in CompileStoreGlobal. |
| 6272 { REG(rbx), REG(rcx), REG(rdx), OMIT_REMEMBERED_SET }, | 6284 { REG(rbx), REG(rcx), REG(rdx), OMIT_REMEMBERED_SET }, |
| 6273 // Used in StoreStubCompiler::CompileStoreField and | 6285 // Used in StoreStubCompiler::CompileStoreField and |
| 6274 // KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. | 6286 // KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. |
| 6275 { REG(rdx), REG(rcx), REG(rbx), EMIT_REMEMBERED_SET }, | 6287 { REG(rdx), REG(rcx), REG(rbx), EMIT_REMEMBERED_SET }, |
| 6276 // GenerateStoreField calls the stub with two different permutations of | 6288 // GenerateStoreField calls the stub with two different permutations of |
| 6277 // registers. This is the second. | 6289 // registers. This is the second. |
| 6278 { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET }, | 6290 { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET }, |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6712 #endif | 6724 #endif |
| 6713 | 6725 |
| 6714 __ Ret(); | 6726 __ Ret(); |
| 6715 } | 6727 } |
| 6716 | 6728 |
| 6717 #undef __ | 6729 #undef __ |
| 6718 | 6730 |
| 6719 } } // namespace v8::internal | 6731 } } // namespace v8::internal |
| 6720 | 6732 |
| 6721 #endif // V8_TARGET_ARCH_X64 | 6733 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |